@2112-lab/central-plant 0.1.78 → 0.1.80
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/dist/bundle/index.js +647 -334
- package/dist/cjs/src/core/centralPlant.js +1 -1
- package/dist/cjs/src/core/centralPlantInternals.js +21 -2
- package/dist/cjs/src/core/sceneViewer.js +11 -1
- package/dist/cjs/src/index.js +2 -0
- package/dist/cjs/src/managers/controls/componentDragManager.js +48 -13
- package/dist/cjs/src/managers/environment/environmentManager.js +188 -310
- package/dist/cjs/src/managers/environment/textureConfig.js +23 -2
- package/dist/cjs/src/managers/scene/animationManager.js +20 -6
- package/dist/cjs/src/managers/scene/componentTooltipManager.js +340 -0
- package/dist/cjs/src/rendering/rendering3D.js +25 -0
- package/dist/esm/src/core/centralPlant.js +1 -1
- package/dist/esm/src/core/centralPlantInternals.js +21 -2
- package/dist/esm/src/core/sceneViewer.js +11 -1
- package/dist/esm/src/index.js +1 -0
- package/dist/esm/src/managers/controls/componentDragManager.js +48 -13
- package/dist/esm/src/managers/environment/environmentManager.js +189 -311
- package/dist/esm/src/managers/environment/textureConfig.js +24 -3
- package/dist/esm/src/managers/scene/animationManager.js +20 -6
- package/dist/esm/src/managers/scene/componentTooltipManager.js +316 -0
- package/dist/esm/src/rendering/rendering3D.js +25 -0
- package/package.json +1 -1
package/dist/bundle/index.js
CHANGED
|
@@ -24701,6 +24701,8 @@ class RGBELoader extends THREE.DataTextureLoader {
|
|
|
24701
24701
|
|
|
24702
24702
|
}
|
|
24703
24703
|
|
|
24704
|
+
/** Maximum anisotropy to apply (caps GPU memory for mip storage) */
|
|
24705
|
+
var MAX_ANISOTROPY = 4;
|
|
24704
24706
|
var TEXTURE_SETS = {
|
|
24705
24707
|
// Light metallic texture using the gravel_embedded_concrete with metallic properties
|
|
24706
24708
|
light_metal: {
|
|
@@ -24837,10 +24839,29 @@ function _loadTextureSet() {
|
|
|
24837
24839
|
return Promise.all(promises);
|
|
24838
24840
|
case 2:
|
|
24839
24841
|
loadedTextures = _context2.v;
|
|
24840
|
-
textureMap = Object.fromEntries(loadedTextures); // Apply texture settings
|
|
24841
|
-
Object.
|
|
24842
|
+
textureMap = Object.fromEntries(loadedTextures); // Apply texture settings with memory-conscious defaults
|
|
24843
|
+
Object.entries(textureMap).forEach(function (_ref4) {
|
|
24844
|
+
var _ref5 = _slicedToArray(_ref4, 2),
|
|
24845
|
+
type = _ref5[0],
|
|
24846
|
+
texture = _ref5[1];
|
|
24842
24847
|
texture.wrapS = texture.wrapT = THREE__namespace.RepeatWrapping;
|
|
24843
24848
|
texture.repeat.set(textureSet.repeat.x, textureSet.repeat.y);
|
|
24849
|
+
|
|
24850
|
+
// Correct colour-space: diffuse is sRGB, everything else is linear data
|
|
24851
|
+
if (type === 'diffuse') {
|
|
24852
|
+
texture.colorSpace = THREE__namespace.SRGBColorSpace;
|
|
24853
|
+
} else {
|
|
24854
|
+
texture.colorSpace = THREE__namespace.LinearSRGBColorSpace;
|
|
24855
|
+
}
|
|
24856
|
+
|
|
24857
|
+
// Roughness maps don't benefit much from mipmaps — skip them to save GPU memory
|
|
24858
|
+
if (type === 'roughness') {
|
|
24859
|
+
texture.generateMipmaps = false;
|
|
24860
|
+
texture.minFilter = THREE__namespace.LinearFilter;
|
|
24861
|
+
}
|
|
24862
|
+
|
|
24863
|
+
// Cap anisotropy to balance quality vs memory
|
|
24864
|
+
texture.anisotropy = MAX_ANISOTROPY;
|
|
24844
24865
|
});
|
|
24845
24866
|
console.log("Texture set ".concat(setName, " loaded successfully"));
|
|
24846
24867
|
return _context2.a(2, {
|
|
@@ -24905,173 +24926,88 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
24905
24926
|
this.sceneViewer = sceneViewer;
|
|
24906
24927
|
}
|
|
24907
24928
|
|
|
24929
|
+
// ──────────────────────────────────────────────
|
|
24930
|
+
// Skybox / environment map
|
|
24931
|
+
// ──────────────────────────────────────────────
|
|
24932
|
+
|
|
24908
24933
|
/**
|
|
24909
|
-
* Create
|
|
24934
|
+
* Create a lightweight procedural sky (default).
|
|
24935
|
+
*
|
|
24936
|
+
* Builds a gradient-sky sphere + hemisphere light, then bakes a small
|
|
24937
|
+
* PMREM environment map for PBR reflections. Total GPU cost is ~1-2 MB
|
|
24938
|
+
* compared to ~50-70 MB for the previous HDR pipeline.
|
|
24910
24939
|
*/
|
|
24911
24940
|
return _createClass(EnvironmentManager, [{
|
|
24912
24941
|
key: "createSkybox",
|
|
24913
|
-
value:
|
|
24942
|
+
value: function () {
|
|
24914
24943
|
var _createSkybox = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
24915
|
-
var component,
|
|
24916
|
-
return _regenerator().w(function (
|
|
24917
|
-
while (1) switch (
|
|
24944
|
+
var component, _t;
|
|
24945
|
+
return _regenerator().w(function (_context) {
|
|
24946
|
+
while (1) switch (_context.n) {
|
|
24918
24947
|
case 0:
|
|
24919
24948
|
component = this.sceneViewer;
|
|
24920
|
-
|
|
24921
|
-
|
|
24922
|
-
|
|
24923
|
-
type: 'hdr',
|
|
24924
|
-
loader: new RGBELoader(),
|
|
24925
|
-
paths: ['/skyboxes/kloofendal_48d_partly_cloudy_puresky_2k.hdr', '/skyboxes/kloofendal_48d_partly_cloudy_puresky_1k.hdr']
|
|
24926
|
-
}, {
|
|
24927
|
-
type: 'jpeg',
|
|
24928
|
-
loader: component.textureLoader,
|
|
24929
|
-
paths: ['/skyboxes/sky_fallback.jpg']
|
|
24930
|
-
}];
|
|
24931
|
-
applyEnvironmentMap = function applyEnvironmentMap(envTexture, type) {
|
|
24932
|
-
try {
|
|
24933
|
-
var _component$scene$envi, _component$scene$back;
|
|
24934
|
-
envTexture.mapping = THREE__namespace.EquirectangularReflectionMapping;
|
|
24935
|
-
var processedEnvMap = pmremGenerator.fromEquirectangular(envTexture).texture;
|
|
24936
|
-
if ((_component$scene$envi = component.scene.environment) !== null && _component$scene$envi !== void 0 && _component$scene$envi.dispose) component.scene.environment.dispose();
|
|
24937
|
-
if ((_component$scene$back = component.scene.background) !== null && _component$scene$back !== void 0 && _component$scene$back.dispose) component.scene.background.dispose();
|
|
24938
|
-
component.scene.environment = processedEnvMap;
|
|
24939
|
-
component.scene.background = processedEnvMap;
|
|
24940
|
-
envTexture.dispose();
|
|
24941
|
-
console.log("\u2705 ".concat(type.toUpperCase(), " environment map applied successfully"));
|
|
24942
|
-
return true;
|
|
24943
|
-
} catch (error) {
|
|
24944
|
-
console.warn("\u274C Failed to apply ".concat(type, " environment map:"), error);
|
|
24945
|
-
return false;
|
|
24946
|
-
}
|
|
24947
|
-
};
|
|
24948
|
-
_loop = /*#__PURE__*/_regenerator().m(function _loop() {
|
|
24949
|
-
var _loaders$_i, type, loader, paths, _iterator, _step, _loop2, _ret2, _t2;
|
|
24950
|
-
return _regenerator().w(function (_context2) {
|
|
24951
|
-
while (1) switch (_context2.n) {
|
|
24952
|
-
case 0:
|
|
24953
|
-
_loaders$_i = _loaders[_i], type = _loaders$_i.type, loader = _loaders$_i.loader, paths = _loaders$_i.paths;
|
|
24954
|
-
_iterator = _createForOfIteratorHelper(paths);
|
|
24955
|
-
_context2.p = 1;
|
|
24956
|
-
_loop2 = /*#__PURE__*/_regenerator().m(function _loop2() {
|
|
24957
|
-
var path, texture, _t;
|
|
24958
|
-
return _regenerator().w(function (_context) {
|
|
24959
|
-
while (1) switch (_context.n) {
|
|
24960
|
-
case 0:
|
|
24961
|
-
path = _step.value;
|
|
24962
|
-
_context.p = 1;
|
|
24963
|
-
console.log("\uD83D\uDD04 Attempting to load ".concat(type.toUpperCase(), ": ").concat(path));
|
|
24964
|
-
_context.n = 2;
|
|
24965
|
-
return new Promise(function (resolve, reject) {
|
|
24966
|
-
var timeout = setTimeout(function () {
|
|
24967
|
-
return reject(new Error('Timeout'));
|
|
24968
|
-
}, 10000);
|
|
24969
|
-
loader.load(path, function (tex) {
|
|
24970
|
-
clearTimeout(timeout);
|
|
24971
|
-
resolve(tex);
|
|
24972
|
-
}, undefined, function (err) {
|
|
24973
|
-
clearTimeout(timeout);
|
|
24974
|
-
reject(err);
|
|
24975
|
-
});
|
|
24976
|
-
});
|
|
24977
|
-
case 2:
|
|
24978
|
-
texture = _context.v;
|
|
24979
|
-
if (!applyEnvironmentMap(texture, type)) {
|
|
24980
|
-
_context.n = 3;
|
|
24981
|
-
break;
|
|
24982
|
-
}
|
|
24983
|
-
pmremGenerator.dispose();
|
|
24984
|
-
return _context.a(2, {
|
|
24985
|
-
v: {
|
|
24986
|
-
v: void 0
|
|
24987
|
-
}
|
|
24988
|
-
});
|
|
24989
|
-
case 3:
|
|
24990
|
-
_context.n = 5;
|
|
24991
|
-
break;
|
|
24992
|
-
case 4:
|
|
24993
|
-
_context.p = 4;
|
|
24994
|
-
_t = _context.v;
|
|
24995
|
-
console.warn("\u26A0\uFE0F Failed to load ".concat(path, ":"), _t.message);
|
|
24996
|
-
case 5:
|
|
24997
|
-
return _context.a(2);
|
|
24998
|
-
}
|
|
24999
|
-
}, _loop2, null, [[1, 4]]);
|
|
25000
|
-
});
|
|
25001
|
-
_iterator.s();
|
|
25002
|
-
case 2:
|
|
25003
|
-
if ((_step = _iterator.n()).done) {
|
|
25004
|
-
_context2.n = 5;
|
|
25005
|
-
break;
|
|
25006
|
-
}
|
|
25007
|
-
return _context2.d(_regeneratorValues(_loop2()), 3);
|
|
25008
|
-
case 3:
|
|
25009
|
-
_ret2 = _context2.v;
|
|
25010
|
-
if (!_ret2) {
|
|
25011
|
-
_context2.n = 4;
|
|
25012
|
-
break;
|
|
25013
|
-
}
|
|
25014
|
-
return _context2.a(2, _ret2.v);
|
|
25015
|
-
case 4:
|
|
25016
|
-
_context2.n = 2;
|
|
25017
|
-
break;
|
|
25018
|
-
case 5:
|
|
25019
|
-
_context2.n = 7;
|
|
25020
|
-
break;
|
|
25021
|
-
case 6:
|
|
25022
|
-
_context2.p = 6;
|
|
25023
|
-
_t2 = _context2.v;
|
|
25024
|
-
_iterator.e(_t2);
|
|
25025
|
-
case 7:
|
|
25026
|
-
_context2.p = 7;
|
|
25027
|
-
_iterator.f();
|
|
25028
|
-
return _context2.f(7);
|
|
25029
|
-
case 8:
|
|
25030
|
-
return _context2.a(2);
|
|
25031
|
-
}
|
|
25032
|
-
}, _loop, null, [[1, 6, 7, 8]]);
|
|
25033
|
-
});
|
|
25034
|
-
_i = 0, _loaders = loaders;
|
|
25035
|
-
case 1:
|
|
25036
|
-
if (!(_i < _loaders.length)) {
|
|
25037
|
-
_context3.n = 4;
|
|
25038
|
-
break;
|
|
25039
|
-
}
|
|
25040
|
-
return _context3.d(_regeneratorValues(_loop()), 2);
|
|
24949
|
+
_context.p = 1;
|
|
24950
|
+
_context.n = 2;
|
|
24951
|
+
return this._applyProceduralSky(component);
|
|
25041
24952
|
case 2:
|
|
25042
|
-
|
|
25043
|
-
|
|
25044
|
-
_context3.n = 3;
|
|
25045
|
-
break;
|
|
25046
|
-
}
|
|
25047
|
-
return _context3.a(2, _ret.v);
|
|
25048
|
-
case 3:
|
|
25049
|
-
_i++;
|
|
25050
|
-
_context3.n = 1;
|
|
24953
|
+
console.log('✅ Procedural sky environment applied');
|
|
24954
|
+
_context.n = 4;
|
|
25051
24955
|
break;
|
|
24956
|
+
case 3:
|
|
24957
|
+
_context.p = 3;
|
|
24958
|
+
_t = _context.v;
|
|
24959
|
+
console.warn('⚠️ Procedural sky failed, applying plain color fallback:', _t);
|
|
24960
|
+
this.setColorBackground();
|
|
25052
24961
|
case 4:
|
|
25053
|
-
|
|
25054
|
-
ambientLight = new THREE__namespace.AmbientLight(0xffffff, 0.6);
|
|
25055
|
-
component.scene.add(ambientLight);
|
|
25056
|
-
skyScene = new THREE__namespace.Scene(); // Create hemisphere light with Z-up orientation - sky color up, ground color down
|
|
25057
|
-
skyScene.add(new THREE__namespace.HemisphereLight(0x87CEEB, 0x444477, 1));
|
|
25058
|
-
component.scene.environment = pmremGenerator.fromScene(skyScene).texture;
|
|
25059
|
-
component.scene.background = new THREE__namespace.Color(0x87CEEB);
|
|
25060
|
-
pmremGenerator.dispose();
|
|
25061
|
-
case 5:
|
|
25062
|
-
return _context3.a(2);
|
|
24962
|
+
return _context.a(2);
|
|
25063
24963
|
}
|
|
25064
|
-
}, _callee, this);
|
|
24964
|
+
}, _callee, this, [[1, 3]]);
|
|
25065
24965
|
}));
|
|
25066
24966
|
function createSkybox() {
|
|
25067
24967
|
return _createSkybox.apply(this, arguments);
|
|
25068
24968
|
}
|
|
25069
24969
|
return createSkybox;
|
|
25070
24970
|
}()
|
|
24971
|
+
/**
|
|
24972
|
+
* Build a procedural sky environment.
|
|
24973
|
+
*
|
|
24974
|
+
* Uses two separate, lightweight resources:
|
|
24975
|
+
* - **Background**: Canvas-rendered gradient texture mapped as equirectangular
|
|
24976
|
+
* (512 × 256 px ≈ 0.5 MB GPU).
|
|
24977
|
+
* - **Environment**: PMREM baked from a HemisphereLight scene for PBR IBL
|
|
24978
|
+
* reflections (~1 MB GPU).
|
|
24979
|
+
*
|
|
24980
|
+
* Custom ShaderMaterials are intentionally avoided inside the PMREM pipeline
|
|
24981
|
+
* because `PMREMGenerator.fromScene()` uses its own cube-face cameras that
|
|
24982
|
+
* can produce black output with non-standard shaders.
|
|
24983
|
+
* @private
|
|
24984
|
+
*/
|
|
24985
|
+
}, {
|
|
24986
|
+
key: "_applyProceduralSky",
|
|
24987
|
+
value: function _applyProceduralSky(component) {
|
|
24988
|
+
var _component$scene$envi, _component$scene$back;
|
|
24989
|
+
// Dispose of existing textures
|
|
24990
|
+
if ((_component$scene$envi = component.scene.environment) !== null && _component$scene$envi !== void 0 && _component$scene$envi.dispose) component.scene.environment.dispose();
|
|
24991
|
+
if ((_component$scene$back = component.scene.background) !== null && _component$scene$back !== void 0 && _component$scene$back.dispose) component.scene.background.dispose();
|
|
24992
|
+
|
|
24993
|
+
// ── 1. Solid-colour background ──────────────────────────────────────────
|
|
24994
|
+
// A plain THREE.Color is coordinate-system agnostic (no equirectangular
|
|
24995
|
+
// mapping that assumes Y-up), cheap (zero GPU textures), and looks clean.
|
|
24996
|
+
component.scene.background = new THREE__namespace.Color(0xbcddeb); // light sky blue
|
|
24997
|
+
|
|
24998
|
+
// ── 2. PMREM env-map from HemisphereLight for PBR IBL reflections ───────
|
|
24999
|
+
// Intensity must be high enough to light MeshPhysicalMaterial surfaces
|
|
25000
|
+
// that the directional lights don't reach evenly (wall backs, crevices).
|
|
25001
|
+
var pmremGenerator = new THREE__namespace.PMREMGenerator(component.renderer);
|
|
25002
|
+
var lightScene = new THREE__namespace.Scene();
|
|
25003
|
+
lightScene.add(new THREE__namespace.HemisphereLight(0xbcddeb, 0x444477, 3.0));
|
|
25004
|
+
component.scene.environment = pmremGenerator.fromScene(lightScene).texture;
|
|
25005
|
+
pmremGenerator.dispose();
|
|
25006
|
+
}
|
|
25007
|
+
|
|
25071
25008
|
/**
|
|
25072
25009
|
* Setup scene lighting
|
|
25073
25010
|
*/
|
|
25074
|
-
)
|
|
25075
25011
|
}, {
|
|
25076
25012
|
key: "setupLighting",
|
|
25077
25013
|
value: function setupLighting() {
|
|
@@ -25097,15 +25033,27 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
25097
25033
|
component.scene.add(sunLight);
|
|
25098
25034
|
// component.scene.add(sunLight.target)
|
|
25099
25035
|
|
|
25100
|
-
//
|
|
25101
|
-
//
|
|
25102
|
-
|
|
25036
|
+
// Flat ambient light – ensures no surface is ever fully black regardless
|
|
25037
|
+
// of orientation. Low intensity so it doesn't wash out lit surfaces.
|
|
25038
|
+
var flatAmbient = new THREE__namespace.AmbientLight(0xffffff, 1.0);
|
|
25039
|
+
component.scene.add(flatAmbient);
|
|
25040
|
+
|
|
25041
|
+
// Hemispheric ambient – adds sky/ground colour tint on surfaces the
|
|
25042
|
+
// directional lights miss (essential without an HDR environment map).
|
|
25043
|
+
var ambientLight = new THREE__namespace.HemisphereLight(0xffffff, 0x444466, 1.0);
|
|
25044
|
+
component.scene.add(ambientLight);
|
|
25103
25045
|
|
|
25104
25046
|
// Fill light (secondary directional light) - adjusted for Z-up coordinate system with flipped Y
|
|
25105
|
-
var fillLight = new THREE__namespace.DirectionalLight(0xffffff,
|
|
25047
|
+
var fillLight = new THREE__namespace.DirectionalLight(0xffffff, 3.0);
|
|
25106
25048
|
fillLight.position.set(10, -10, 10); // X=-10, Y=-10 (flipped), Z=10 (up in Z-up system)
|
|
25107
25049
|
component.scene.add(fillLight);
|
|
25108
25050
|
|
|
25051
|
+
// Back-fill light – illuminates rear-facing walls and equipment backs
|
|
25052
|
+
// that the sun and primary fill can't reach.
|
|
25053
|
+
var backFillLight = new THREE__namespace.DirectionalLight(0xddeeff, 3.0);
|
|
25054
|
+
backFillLight.position.set(-10, 10, 8);
|
|
25055
|
+
component.scene.add(backFillLight);
|
|
25056
|
+
|
|
25109
25057
|
// // Rim light (for edge definition)
|
|
25110
25058
|
// const rimLight = new THREE.DirectionalLight(0xffffff, 0.9)
|
|
25111
25059
|
// rimLight.position.set(0, 0, -20)
|
|
@@ -25134,9 +25082,9 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
25134
25082
|
key: "addTexturedGround",
|
|
25135
25083
|
value: (function () {
|
|
25136
25084
|
var _addTexturedGround = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
|
|
25137
|
-
var component, groundSize, groundGeometry, groundMaterial, ground, texturedMaterial,
|
|
25138
|
-
return _regenerator().w(function (
|
|
25139
|
-
while (1) switch (
|
|
25085
|
+
var component, groundSize, groundGeometry, groundMaterial, ground, texturedMaterial, _t2;
|
|
25086
|
+
return _regenerator().w(function (_context2) {
|
|
25087
|
+
while (1) switch (_context2.n) {
|
|
25140
25088
|
case 0:
|
|
25141
25089
|
component = this.sceneViewer;
|
|
25142
25090
|
console.debug('Starting addTexturedGround...');
|
|
@@ -25155,23 +25103,23 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
25155
25103
|
ground.uuid = 'GROUND'; // Set UUID to match JSON data structure
|
|
25156
25104
|
ground.userData.isBaseGround = true;
|
|
25157
25105
|
component.scene.add(ground);
|
|
25158
|
-
|
|
25106
|
+
_context2.p = 1;
|
|
25159
25107
|
console.debug('Loading concrete texture set...');
|
|
25160
|
-
|
|
25108
|
+
_context2.n = 2;
|
|
25161
25109
|
return loadTextureSetAndCreateMaterial('gravel_embedded_concrete', component.textureLoader);
|
|
25162
25110
|
case 2:
|
|
25163
|
-
texturedMaterial =
|
|
25111
|
+
texturedMaterial = _context2.v;
|
|
25164
25112
|
ground.material = texturedMaterial;
|
|
25165
25113
|
ground.material.needsUpdate = true;
|
|
25166
25114
|
console.log('✅ Ground material updated with textures');
|
|
25167
|
-
|
|
25115
|
+
_context2.n = 4;
|
|
25168
25116
|
break;
|
|
25169
25117
|
case 3:
|
|
25170
|
-
|
|
25171
|
-
|
|
25172
|
-
console.warn('Error loading ground textures:',
|
|
25118
|
+
_context2.p = 3;
|
|
25119
|
+
_t2 = _context2.v;
|
|
25120
|
+
console.warn('Error loading ground textures:', _t2);
|
|
25173
25121
|
case 4:
|
|
25174
|
-
return
|
|
25122
|
+
return _context2.a(2);
|
|
25175
25123
|
}
|
|
25176
25124
|
}, _callee2, this, [[1, 3]]);
|
|
25177
25125
|
}));
|
|
@@ -25188,9 +25136,9 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
25188
25136
|
key: "addBrickWalls",
|
|
25189
25137
|
value: (function () {
|
|
25190
25138
|
var _addBrickWalls = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
|
|
25191
|
-
var component, wallHeight, wallThickness, groundSize, halfGroundSize, brickMaterial, createWalls, texturedBrickMaterial,
|
|
25192
|
-
return _regenerator().w(function (
|
|
25193
|
-
while (1) switch (
|
|
25139
|
+
var component, wallHeight, wallThickness, groundSize, halfGroundSize, brickMaterial, createWalls, texturedBrickMaterial, _t3;
|
|
25140
|
+
return _regenerator().w(function (_context3) {
|
|
25141
|
+
while (1) switch (_context3.n) {
|
|
25194
25142
|
case 0:
|
|
25195
25143
|
component = this.sceneViewer;
|
|
25196
25144
|
console.debug('Starting addBrickWalls...');
|
|
@@ -25292,12 +25240,12 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
25292
25240
|
};
|
|
25293
25241
|
createWalls(brickMaterial);
|
|
25294
25242
|
console.debug('Basic brick walls created');
|
|
25295
|
-
|
|
25243
|
+
_context3.p = 1;
|
|
25296
25244
|
console.debug('Loading brick texture set...');
|
|
25297
|
-
|
|
25245
|
+
_context3.n = 2;
|
|
25298
25246
|
return loadTextureSetAndCreateMaterial('brick', component.textureLoader);
|
|
25299
25247
|
case 2:
|
|
25300
|
-
texturedBrickMaterial =
|
|
25248
|
+
texturedBrickMaterial = _context3.v;
|
|
25301
25249
|
component.scene.traverse(function (object) {
|
|
25302
25250
|
if (object.isMesh && object.userData.isBrickWall) {
|
|
25303
25251
|
object.material = texturedBrickMaterial;
|
|
@@ -25305,14 +25253,14 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
25305
25253
|
}
|
|
25306
25254
|
});
|
|
25307
25255
|
console.log('✅ Brick walls updated with textures');
|
|
25308
|
-
|
|
25256
|
+
_context3.n = 4;
|
|
25309
25257
|
break;
|
|
25310
25258
|
case 3:
|
|
25311
|
-
|
|
25312
|
-
|
|
25313
|
-
console.warn('Error loading brick textures:',
|
|
25259
|
+
_context3.p = 3;
|
|
25260
|
+
_t3 = _context3.v;
|
|
25261
|
+
console.warn('Error loading brick textures:', _t3);
|
|
25314
25262
|
case 4:
|
|
25315
|
-
return
|
|
25263
|
+
return _context3.a(2);
|
|
25316
25264
|
}
|
|
25317
25265
|
}, _callee3, this, [[1, 3]]);
|
|
25318
25266
|
}));
|
|
@@ -25361,23 +25309,23 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
25361
25309
|
key: "initializeEnvironment",
|
|
25362
25310
|
value: (function () {
|
|
25363
25311
|
var _initializeEnvironment = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
|
|
25364
|
-
return _regenerator().w(function (
|
|
25365
|
-
while (1) switch (
|
|
25312
|
+
return _regenerator().w(function (_context4) {
|
|
25313
|
+
while (1) switch (_context4.n) {
|
|
25366
25314
|
case 0:
|
|
25367
|
-
|
|
25315
|
+
_context4.n = 1;
|
|
25368
25316
|
return this.createSkybox();
|
|
25369
25317
|
case 1:
|
|
25370
25318
|
this.setupLighting();
|
|
25371
|
-
|
|
25319
|
+
_context4.n = 2;
|
|
25372
25320
|
return this.addTexturedGround();
|
|
25373
25321
|
case 2:
|
|
25374
|
-
|
|
25322
|
+
_context4.n = 3;
|
|
25375
25323
|
return this.addBrickWalls();
|
|
25376
25324
|
case 3:
|
|
25377
25325
|
this.addHorizonFog();
|
|
25378
25326
|
console.log('Environment initialization completed');
|
|
25379
25327
|
case 4:
|
|
25380
|
-
return
|
|
25328
|
+
return _context4.a(2);
|
|
25381
25329
|
}
|
|
25382
25330
|
}, _callee4, this);
|
|
25383
25331
|
}));
|
|
@@ -25418,60 +25366,50 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
25418
25366
|
|
|
25419
25367
|
/**
|
|
25420
25368
|
* Set the skybox type dynamically
|
|
25421
|
-
* @param {
|
|
25369
|
+
* @param {'Procedural'|'HDR'|'Color'} skyboxType
|
|
25422
25370
|
*/
|
|
25423
25371
|
}, {
|
|
25424
25372
|
key: "setSkyboxType",
|
|
25425
25373
|
value: (function () {
|
|
25426
25374
|
var _setSkyboxType = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(skyboxType) {
|
|
25427
|
-
var component, _component$scene$envi3, _component$scene$back3,
|
|
25428
|
-
return _regenerator().w(function (
|
|
25429
|
-
while (1) switch (
|
|
25375
|
+
var component, _component$scene$envi3, _component$scene$back3, _t4, _t5;
|
|
25376
|
+
return _regenerator().w(function (_context5) {
|
|
25377
|
+
while (1) switch (_context5.n) {
|
|
25430
25378
|
case 0:
|
|
25431
25379
|
component = this.sceneViewer;
|
|
25432
|
-
|
|
25380
|
+
_context5.p = 1;
|
|
25433
25381
|
console.log("\uD83C\uDF0C Changing skybox type to: ".concat(skyboxType));
|
|
25434
25382
|
|
|
25435
25383
|
// Dispose of current environment textures
|
|
25436
|
-
if ((_component$scene$envi3 = component.scene.environment) !== null && _component$scene$envi3 !== void 0 && _component$scene$envi3.dispose)
|
|
25437
|
-
|
|
25438
|
-
|
|
25439
|
-
|
|
25440
|
-
component.scene.background.dispose();
|
|
25441
|
-
}
|
|
25442
|
-
_pmremGenerator = new THREE__namespace.PMREMGenerator(component.renderer);
|
|
25443
|
-
_pmremGenerator.compileEquirectangularShader();
|
|
25444
|
-
_t5 = skyboxType;
|
|
25445
|
-
_context7.n = _t5 === 'HDR' ? 2 : _t5 === 'Fallback' ? 4 : _t5 === 'Color' ? 6 : 7;
|
|
25384
|
+
if ((_component$scene$envi3 = component.scene.environment) !== null && _component$scene$envi3 !== void 0 && _component$scene$envi3.dispose) component.scene.environment.dispose();
|
|
25385
|
+
if ((_component$scene$back3 = component.scene.background) !== null && _component$scene$back3 !== void 0 && _component$scene$back3.dispose) component.scene.background.dispose();
|
|
25386
|
+
_t4 = skyboxType;
|
|
25387
|
+
_context5.n = _t4 === 'Procedural' ? 2 : _t4 === 'HDR' ? 3 : _t4 === 'Color' ? 5 : 6;
|
|
25446
25388
|
break;
|
|
25447
25389
|
case 2:
|
|
25448
|
-
|
|
25449
|
-
return
|
|
25390
|
+
this._applyProceduralSky(component);
|
|
25391
|
+
return _context5.a(3, 7);
|
|
25450
25392
|
case 3:
|
|
25451
|
-
|
|
25393
|
+
_context5.n = 4;
|
|
25394
|
+
return this._loadHDRSkybox(component);
|
|
25452
25395
|
case 4:
|
|
25453
|
-
|
|
25454
|
-
return this.loadFallbackSkybox(_pmremGenerator);
|
|
25396
|
+
return _context5.a(3, 7);
|
|
25455
25397
|
case 5:
|
|
25456
|
-
|
|
25398
|
+
this._setColorBackground(component);
|
|
25399
|
+
return _context5.a(3, 7);
|
|
25457
25400
|
case 6:
|
|
25458
|
-
|
|
25459
|
-
|
|
25401
|
+
console.warn("Unknown skybox type: ".concat(skyboxType, ", using Procedural"));
|
|
25402
|
+
this._applyProceduralSky(component);
|
|
25460
25403
|
case 7:
|
|
25461
|
-
console.
|
|
25462
|
-
|
|
25463
|
-
return this.loadHDRSkybox(_pmremGenerator);
|
|
25404
|
+
console.log("\u2705 Skybox type changed to: ".concat(skyboxType));
|
|
25405
|
+
return _context5.a(2, true);
|
|
25464
25406
|
case 8:
|
|
25465
|
-
|
|
25466
|
-
|
|
25467
|
-
|
|
25468
|
-
|
|
25469
|
-
_context7.p = 9;
|
|
25470
|
-
_t6 = _context7.v;
|
|
25471
|
-
console.error('❌ Error setting skybox type:', _t6);
|
|
25472
|
-
return _context7.a(2, false);
|
|
25407
|
+
_context5.p = 8;
|
|
25408
|
+
_t5 = _context5.v;
|
|
25409
|
+
console.error('❌ Error setting skybox type:', _t5);
|
|
25410
|
+
return _context5.a(2, false);
|
|
25473
25411
|
}
|
|
25474
|
-
}, _callee5, this, [[1,
|
|
25412
|
+
}, _callee5, this, [[1, 8]]);
|
|
25475
25413
|
}));
|
|
25476
25414
|
function setSkyboxType(_x) {
|
|
25477
25415
|
return _setSkyboxType.apply(this, arguments);
|
|
@@ -25479,29 +25417,34 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
25479
25417
|
return setSkyboxType;
|
|
25480
25418
|
}()
|
|
25481
25419
|
/**
|
|
25482
|
-
* Load HDR skybox
|
|
25420
|
+
* Load HDR skybox on demand (high quality, high memory).
|
|
25421
|
+
* Tries 1k first to save memory; falls back to color on failure.
|
|
25422
|
+
* @private
|
|
25483
25423
|
*/
|
|
25484
25424
|
)
|
|
25485
25425
|
}, {
|
|
25486
|
-
key: "
|
|
25426
|
+
key: "_loadHDRSkybox",
|
|
25487
25427
|
value: (function () {
|
|
25488
|
-
var
|
|
25489
|
-
var
|
|
25490
|
-
return _regenerator().w(function (
|
|
25491
|
-
while (1) switch (
|
|
25428
|
+
var _loadHDRSkybox2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(component) {
|
|
25429
|
+
var rgbeLoader, pmremGenerator, hdrPaths, _loop, _ret, _i, _hdrPaths;
|
|
25430
|
+
return _regenerator().w(function (_context7) {
|
|
25431
|
+
while (1) switch (_context7.n) {
|
|
25492
25432
|
case 0:
|
|
25493
|
-
component = this.sceneViewer;
|
|
25494
25433
|
rgbeLoader = new RGBELoader();
|
|
25495
|
-
|
|
25496
|
-
|
|
25497
|
-
|
|
25498
|
-
|
|
25499
|
-
|
|
25434
|
+
pmremGenerator = new THREE__namespace.PMREMGenerator(component.renderer);
|
|
25435
|
+
pmremGenerator.compileEquirectangularShader();
|
|
25436
|
+
|
|
25437
|
+
// Prefer the 1k variant (~20 MB GPU) over 2k (~50 MB GPU)
|
|
25438
|
+
hdrPaths = ['/skyboxes/kloofendal_48d_partly_cloudy_puresky_1k.hdr', '/skyboxes/kloofendal_48d_partly_cloudy_puresky_2k.hdr'];
|
|
25439
|
+
_loop = /*#__PURE__*/_regenerator().m(function _loop() {
|
|
25440
|
+
var path, texture, processedEnvMap, _t6;
|
|
25441
|
+
return _regenerator().w(function (_context6) {
|
|
25442
|
+
while (1) switch (_context6.n) {
|
|
25500
25443
|
case 0:
|
|
25501
|
-
path = _hdrPaths[
|
|
25502
|
-
|
|
25444
|
+
path = _hdrPaths[_i];
|
|
25445
|
+
_context6.p = 1;
|
|
25503
25446
|
console.log("\uD83D\uDD04 Loading HDR: ".concat(path));
|
|
25504
|
-
|
|
25447
|
+
_context6.n = 2;
|
|
25505
25448
|
return new Promise(function (resolve, reject) {
|
|
25506
25449
|
var timeout = setTimeout(function () {
|
|
25507
25450
|
return reject(new Error('Timeout'));
|
|
@@ -25515,123 +25458,79 @@ var EnvironmentManager = /*#__PURE__*/function () {
|
|
|
25515
25458
|
});
|
|
25516
25459
|
});
|
|
25517
25460
|
case 2:
|
|
25518
|
-
texture =
|
|
25461
|
+
texture = _context6.v;
|
|
25519
25462
|
texture.mapping = THREE__namespace.EquirectangularReflectionMapping;
|
|
25520
25463
|
processedEnvMap = pmremGenerator.fromEquirectangular(texture).texture;
|
|
25521
25464
|
component.scene.environment = processedEnvMap;
|
|
25522
25465
|
component.scene.background = processedEnvMap;
|
|
25523
25466
|
texture.dispose();
|
|
25467
|
+
pmremGenerator.dispose();
|
|
25524
25468
|
console.log('✅ HDR skybox loaded successfully');
|
|
25525
|
-
return
|
|
25469
|
+
return _context6.a(2, {
|
|
25526
25470
|
v: void 0
|
|
25527
25471
|
});
|
|
25528
25472
|
case 3:
|
|
25529
|
-
|
|
25530
|
-
|
|
25531
|
-
console.warn("\u26A0\uFE0F Failed to load HDR skybox ".concat(path, ":"),
|
|
25473
|
+
_context6.p = 3;
|
|
25474
|
+
_t6 = _context6.v;
|
|
25475
|
+
console.warn("\u26A0\uFE0F Failed to load HDR skybox ".concat(path, ":"), _t6.message);
|
|
25532
25476
|
case 4:
|
|
25533
|
-
return
|
|
25477
|
+
return _context6.a(2);
|
|
25534
25478
|
}
|
|
25535
|
-
},
|
|
25479
|
+
}, _loop, null, [[1, 3]]);
|
|
25536
25480
|
});
|
|
25537
|
-
|
|
25481
|
+
_i = 0, _hdrPaths = hdrPaths;
|
|
25538
25482
|
case 1:
|
|
25539
|
-
if (!(
|
|
25540
|
-
|
|
25483
|
+
if (!(_i < _hdrPaths.length)) {
|
|
25484
|
+
_context7.n = 4;
|
|
25541
25485
|
break;
|
|
25542
25486
|
}
|
|
25543
|
-
return
|
|
25487
|
+
return _context7.d(_regeneratorValues(_loop()), 2);
|
|
25544
25488
|
case 2:
|
|
25545
|
-
|
|
25546
|
-
if (!
|
|
25547
|
-
|
|
25489
|
+
_ret = _context7.v;
|
|
25490
|
+
if (!_ret) {
|
|
25491
|
+
_context7.n = 3;
|
|
25548
25492
|
break;
|
|
25549
25493
|
}
|
|
25550
|
-
return
|
|
25494
|
+
return _context7.a(2, _ret.v);
|
|
25551
25495
|
case 3:
|
|
25552
|
-
|
|
25553
|
-
|
|
25496
|
+
_i++;
|
|
25497
|
+
_context7.n = 1;
|
|
25554
25498
|
break;
|
|
25555
25499
|
case 4:
|
|
25500
|
+
pmremGenerator.dispose();
|
|
25556
25501
|
throw new Error('Failed to load any HDR skybox');
|
|
25557
25502
|
case 5:
|
|
25558
|
-
return
|
|
25503
|
+
return _context7.a(2);
|
|
25559
25504
|
}
|
|
25560
|
-
}, _callee6
|
|
25505
|
+
}, _callee6);
|
|
25561
25506
|
}));
|
|
25562
|
-
function
|
|
25563
|
-
return
|
|
25507
|
+
function _loadHDRSkybox(_x2) {
|
|
25508
|
+
return _loadHDRSkybox2.apply(this, arguments);
|
|
25564
25509
|
}
|
|
25565
|
-
return
|
|
25510
|
+
return _loadHDRSkybox;
|
|
25566
25511
|
}()
|
|
25567
25512
|
/**
|
|
25568
|
-
*
|
|
25513
|
+
* Set solid color background with basic ambient lighting.
|
|
25514
|
+
* @private
|
|
25569
25515
|
*/
|
|
25570
25516
|
)
|
|
25571
25517
|
}, {
|
|
25572
|
-
key: "
|
|
25573
|
-
value:
|
|
25574
|
-
|
|
25575
|
-
|
|
25576
|
-
|
|
25577
|
-
|
|
25578
|
-
|
|
25579
|
-
|
|
25580
|
-
|
|
25581
|
-
console.log('🔄 Loading fallback skybox');
|
|
25582
|
-
_context0.n = 2;
|
|
25583
|
-
return new Promise(function (resolve, reject) {
|
|
25584
|
-
var timeout = setTimeout(function () {
|
|
25585
|
-
return reject(new Error('Timeout'));
|
|
25586
|
-
}, 10000);
|
|
25587
|
-
component.textureLoader.load('/skyboxes/sky_fallback.jpg', function (tex) {
|
|
25588
|
-
clearTimeout(timeout);
|
|
25589
|
-
resolve(tex);
|
|
25590
|
-
}, undefined, function (err) {
|
|
25591
|
-
clearTimeout(timeout);
|
|
25592
|
-
reject(err);
|
|
25593
|
-
});
|
|
25594
|
-
});
|
|
25595
|
-
case 2:
|
|
25596
|
-
texture = _context0.v;
|
|
25597
|
-
texture.mapping = THREE__namespace.EquirectangularReflectionMapping;
|
|
25598
|
-
processedEnvMap = pmremGenerator.fromEquirectangular(texture).texture;
|
|
25599
|
-
component.scene.environment = processedEnvMap;
|
|
25600
|
-
component.scene.background = processedEnvMap;
|
|
25601
|
-
texture.dispose();
|
|
25602
|
-
console.log('✅ Fallback skybox loaded successfully');
|
|
25603
|
-
_context0.n = 4;
|
|
25604
|
-
break;
|
|
25605
|
-
case 3:
|
|
25606
|
-
_context0.p = 3;
|
|
25607
|
-
_t8 = _context0.v;
|
|
25608
|
-
console.warn('⚠️ Failed to load fallback skybox:', _t8.message);
|
|
25609
|
-
throw _t8;
|
|
25610
|
-
case 4:
|
|
25611
|
-
return _context0.a(2);
|
|
25612
|
-
}
|
|
25613
|
-
}, _callee7, this, [[1, 3]]);
|
|
25614
|
-
}));
|
|
25615
|
-
function loadFallbackSkybox(_x3) {
|
|
25616
|
-
return _loadFallbackSkybox.apply(this, arguments);
|
|
25617
|
-
}
|
|
25618
|
-
return loadFallbackSkybox;
|
|
25619
|
-
}()
|
|
25518
|
+
key: "_setColorBackground",
|
|
25519
|
+
value: function _setColorBackground(component) {
|
|
25520
|
+
component.scene.environment = null;
|
|
25521
|
+
component.scene.background = new THREE__namespace.Color(0xffffff);
|
|
25522
|
+
var ambientLight = new THREE__namespace.AmbientLight(0xffffff, 0.6);
|
|
25523
|
+
component.scene.add(ambientLight);
|
|
25524
|
+
console.log('✅ Color background set successfully');
|
|
25525
|
+
}
|
|
25526
|
+
|
|
25620
25527
|
/**
|
|
25621
|
-
*
|
|
25528
|
+
* Public convenience alias for setColorBackground (backwards compat)
|
|
25622
25529
|
*/
|
|
25623
|
-
)
|
|
25624
25530
|
}, {
|
|
25625
25531
|
key: "setColorBackground",
|
|
25626
25532
|
value: function setColorBackground() {
|
|
25627
|
-
|
|
25628
|
-
component.scene.environment = null;
|
|
25629
|
-
component.scene.background = new THREE__namespace.Color(0xffffff); // White background
|
|
25630
|
-
|
|
25631
|
-
// Add basic ambient lighting since we don't have environment lighting
|
|
25632
|
-
var ambientLight = new THREE__namespace.AmbientLight(0xffffff, 0.6);
|
|
25633
|
-
component.scene.add(ambientLight);
|
|
25634
|
-
console.log('✅ Color background set successfully');
|
|
25533
|
+
this._setColorBackground(this.sceneViewer);
|
|
25635
25534
|
}
|
|
25636
25535
|
}]);
|
|
25637
25536
|
}();
|
|
@@ -31012,18 +30911,32 @@ var AnimationManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31012
30911
|
if (sceneViewer.performanceMonitorManager) {
|
|
31013
30912
|
sceneViewer.performanceMonitorManager.beginFrame();
|
|
31014
30913
|
}
|
|
30914
|
+
try {
|
|
30915
|
+
// Update controls
|
|
30916
|
+
sceneViewer.controls.update();
|
|
31015
30917
|
|
|
31016
|
-
|
|
31017
|
-
|
|
31018
|
-
|
|
31019
|
-
|
|
31020
|
-
|
|
30918
|
+
// Render the scene
|
|
30919
|
+
sceneViewer.renderer.render(sceneViewer.scene, sceneViewer.camera);
|
|
30920
|
+
} catch (renderError) {
|
|
30921
|
+
// Catch WebGL or rendering errors to prevent the animation loop from
|
|
30922
|
+
// producing a permanent white screen. Log once and continue so that
|
|
30923
|
+
// subsequent frames can recover if the problematic object is removed.
|
|
30924
|
+
if (!this._hasLoggedRenderError) {
|
|
30925
|
+
console.error('❌ AnimationManager: Render error caught — scene may contain disposed resources:', renderError);
|
|
30926
|
+
this._hasLoggedRenderError = true;
|
|
30927
|
+
}
|
|
30928
|
+
}
|
|
31021
30929
|
|
|
31022
30930
|
// Render tooltips if tooltipsManager exists
|
|
31023
30931
|
if (sceneViewer.tooltipsManager) {
|
|
31024
30932
|
sceneViewer.tooltipsManager.render();
|
|
31025
30933
|
}
|
|
31026
30934
|
|
|
30935
|
+
// Update component tooltip screen position
|
|
30936
|
+
if (sceneViewer.componentTooltipManager) {
|
|
30937
|
+
sceneViewer.componentTooltipManager.update();
|
|
30938
|
+
}
|
|
30939
|
+
|
|
31027
30940
|
// End performance monitoring frame
|
|
31028
30941
|
if (sceneViewer.performanceMonitorManager) {
|
|
31029
30942
|
sceneViewer.performanceMonitorManager.endFrame();
|
|
@@ -31394,7 +31307,10 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31394
31307
|
}
|
|
31395
31308
|
this.dragData.previewObject = cachedModel.clone();
|
|
31396
31309
|
|
|
31397
|
-
// Clone materials to
|
|
31310
|
+
// Clone geometries and materials to fully isolate the preview from the cache.
|
|
31311
|
+
// Without this, disposing the preview would invalidate shared GPU buffers
|
|
31312
|
+
// and cause the scene to go white.
|
|
31313
|
+
this._cloneGeometries(this.dragData.previewObject);
|
|
31398
31314
|
this._cloneMaterials(this.dragData.previewObject);
|
|
31399
31315
|
|
|
31400
31316
|
// Store original colors BEFORE making transparent
|
|
@@ -31533,6 +31449,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31533
31449
|
return _context3.a(3, 11);
|
|
31534
31450
|
case 9:
|
|
31535
31451
|
deviceModel = cachedDevice.clone();
|
|
31452
|
+
this._cloneGeometries(deviceModel);
|
|
31536
31453
|
this._cloneMaterials(deviceModel);
|
|
31537
31454
|
this._storeOriginalColors(deviceModel);
|
|
31538
31455
|
deviceModel.userData = {
|
|
@@ -31585,16 +31502,38 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31585
31502
|
if (Array.isArray(child.material)) {
|
|
31586
31503
|
// Handle material arrays
|
|
31587
31504
|
child.material = child.material.map(function (material) {
|
|
31588
|
-
|
|
31505
|
+
var cloned = material.clone();
|
|
31506
|
+
cloned.userData._isClonedMaterial = true;
|
|
31507
|
+
return cloned;
|
|
31589
31508
|
});
|
|
31590
31509
|
} else {
|
|
31591
31510
|
// Handle single materials
|
|
31592
31511
|
child.material = child.material.clone();
|
|
31512
|
+
child.material.userData._isClonedMaterial = true;
|
|
31593
31513
|
}
|
|
31594
31514
|
}
|
|
31595
31515
|
});
|
|
31596
31516
|
}
|
|
31597
31517
|
|
|
31518
|
+
/**
|
|
31519
|
+
* Clone all geometries in an object hierarchy to avoid shared geometry buffer issues.
|
|
31520
|
+
* Three.js Object3D.clone() shares geometry references between the original and clone.
|
|
31521
|
+
* Disposing shared geometry invalidates GPU buffers for ALL objects using that geometry,
|
|
31522
|
+
* which causes the scene to go white. This method gives each mesh its own geometry copy.
|
|
31523
|
+
* @param {THREE.Object3D} object - The object to clone geometries for
|
|
31524
|
+
* @private
|
|
31525
|
+
*/
|
|
31526
|
+
}, {
|
|
31527
|
+
key: "_cloneGeometries",
|
|
31528
|
+
value: function _cloneGeometries(object) {
|
|
31529
|
+
object.traverse(function (child) {
|
|
31530
|
+
if (child.isMesh && child.geometry) {
|
|
31531
|
+
child.geometry = child.geometry.clone();
|
|
31532
|
+
child.userData._isClonedGeometry = true;
|
|
31533
|
+
}
|
|
31534
|
+
});
|
|
31535
|
+
}
|
|
31536
|
+
|
|
31598
31537
|
/**
|
|
31599
31538
|
* Store original colors from all materials in an object hierarchy
|
|
31600
31539
|
* @param {THREE.Object3D} object - The object to store colors from
|
|
@@ -31973,18 +31912,27 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31973
31912
|
if (this.dragData.previewObject) {
|
|
31974
31913
|
this.sceneViewer.scene.remove(this.dragData.previewObject);
|
|
31975
31914
|
|
|
31976
|
-
// Dispose of geometry and materials
|
|
31915
|
+
// Dispose of CLONED geometry and materials only.
|
|
31916
|
+
// Both geometries and materials were cloned during preview creation
|
|
31917
|
+
// via _cloneGeometries() and _cloneMaterials(), so they are safe to dispose.
|
|
31918
|
+
// IMPORTANT: Never dispose geometry/materials that are shared with the model cache.
|
|
31977
31919
|
this.dragData.previewObject.traverse(function (child) {
|
|
31978
|
-
if (child.
|
|
31979
|
-
|
|
31980
|
-
|
|
31981
|
-
|
|
31982
|
-
|
|
31983
|
-
|
|
31984
|
-
|
|
31985
|
-
|
|
31986
|
-
|
|
31987
|
-
|
|
31920
|
+
if (child.isMesh) {
|
|
31921
|
+
// Only dispose geometry if it was cloned for this preview
|
|
31922
|
+
if (child.geometry && child.userData._isClonedGeometry) {
|
|
31923
|
+
child.geometry.dispose();
|
|
31924
|
+
}
|
|
31925
|
+
// Only dispose material if it was cloned for this preview
|
|
31926
|
+
if (child.material) {
|
|
31927
|
+
if (Array.isArray(child.material)) {
|
|
31928
|
+
child.material.forEach(function (material) {
|
|
31929
|
+
if (material.userData._isClonedMaterial) {
|
|
31930
|
+
material.dispose();
|
|
31931
|
+
}
|
|
31932
|
+
});
|
|
31933
|
+
} else if (child.material.userData._isClonedMaterial) {
|
|
31934
|
+
child.material.dispose();
|
|
31935
|
+
}
|
|
31988
31936
|
}
|
|
31989
31937
|
}
|
|
31990
31938
|
});
|
|
@@ -33080,6 +33028,317 @@ var SceneTooltipsManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
33080
33028
|
}]);
|
|
33081
33029
|
}(BaseDisposable);
|
|
33082
33030
|
|
|
33031
|
+
// ---------------------------------------------------------------------------
|
|
33032
|
+
// Inline styles (injected once into the document head)
|
|
33033
|
+
// ---------------------------------------------------------------------------
|
|
33034
|
+
var TOOLTIP_STYLES = "\n.cp-tooltip {\n position: absolute;\n pointer-events: auto;\n z-index: 10000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n user-select: none;\n min-width: 200px;\n max-width: 280px;\n transform: translate(-50%, -100%);\n margin-top: -12px;\n transition: opacity 0.15s ease;\n}\n\n.cp-tooltip__card {\n background: rgba(28, 32, 40, 0.95);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 10px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45);\n overflow: hidden;\n}\n\n/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__header {\n padding: 10px 14px;\n font-weight: 600;\n font-size: 14px;\n color: #e8ecf1;\n background: rgba(255, 255, 255, 0.04);\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n letter-spacing: 0.2px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 I/O Devices section \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__io-section {\n position: relative;\n}\n\n.cp-tooltip__io-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px;\n color: #a4adba;\n cursor: pointer;\n transition: background 0.12s ease, color 0.12s ease;\n}\n\n.cp-tooltip__io-trigger:hover {\n background: rgba(255, 255, 255, 0.06);\n color: #e8ecf1;\n}\n\n.cp-tooltip__io-trigger-label {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.6px;\n font-weight: 500;\n}\n\n.cp-tooltip__io-arrow {\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.cp-tooltip__io-section.expanded .cp-tooltip__io-arrow {\n transform: rotate(90deg);\n}\n\n/* \u2500\u2500 Device list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__device-list {\n max-height: 0;\n overflow: hidden;\n transition: max-height 0.25s ease;\n}\n\n.cp-tooltip__io-section.expanded .cp-tooltip__device-list {\n max-height: 300px;\n}\n\n.cp-tooltip__device-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 14px 6px 20px;\n color: #c1c8d1;\n font-size: 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.04);\n transition: background 0.1s ease;\n}\n\n.cp-tooltip__device-item:hover {\n background: rgba(255, 255, 255, 0.04);\n}\n\n.cp-tooltip__device-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: #4fc3f7;\n flex-shrink: 0;\n}\n\n.cp-tooltip__device-name {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 Empty state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__no-devices {\n padding: 8px 14px;\n color: #6b7280;\n font-size: 12px;\n font-style: italic;\n}\n\n/* \u2500\u2500 Caret arrow pointing down \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.cp-tooltip__caret {\n width: 0;\n height: 0;\n border-left: 7px solid transparent;\n border-right: 7px solid transparent;\n border-top: 7px solid rgba(28, 32, 40, 0.95);\n margin: 0 auto;\n position: relative;\n top: -1px;\n}\n";
|
|
33035
|
+
var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
33036
|
+
/**
|
|
33037
|
+
* @param {Object} sceneViewer - The sceneViewer instance
|
|
33038
|
+
*/
|
|
33039
|
+
function ComponentTooltipManager(sceneViewer) {
|
|
33040
|
+
var _this;
|
|
33041
|
+
_classCallCheck(this, ComponentTooltipManager);
|
|
33042
|
+
_this = _callSuper(this, ComponentTooltipManager);
|
|
33043
|
+
_this.sceneViewer = sceneViewer;
|
|
33044
|
+
_this.selectedObject = null;
|
|
33045
|
+
_this.tooltipEl = null;
|
|
33046
|
+
_this._styleInjected = false;
|
|
33047
|
+
_this._ioExpanded = false;
|
|
33048
|
+
_this._injectStyles();
|
|
33049
|
+
return _this;
|
|
33050
|
+
}
|
|
33051
|
+
|
|
33052
|
+
// -----------------------------------------------------------------------
|
|
33053
|
+
// Lifecycle
|
|
33054
|
+
// -----------------------------------------------------------------------
|
|
33055
|
+
|
|
33056
|
+
/**
|
|
33057
|
+
* Called automatically by BaseDisposable.dispose()
|
|
33058
|
+
* @override
|
|
33059
|
+
*/
|
|
33060
|
+
_inherits(ComponentTooltipManager, _BaseDisposable);
|
|
33061
|
+
return _createClass(ComponentTooltipManager, [{
|
|
33062
|
+
key: "_doDispose",
|
|
33063
|
+
value: function _doDispose() {
|
|
33064
|
+
this.hide();
|
|
33065
|
+
this._removeStyleTag();
|
|
33066
|
+
this.nullifyProperties('sceneViewer', 'selectedObject', 'tooltipEl');
|
|
33067
|
+
}
|
|
33068
|
+
|
|
33069
|
+
// -----------------------------------------------------------------------
|
|
33070
|
+
// Public API
|
|
33071
|
+
// -----------------------------------------------------------------------
|
|
33072
|
+
|
|
33073
|
+
/**
|
|
33074
|
+
* Should be called when an object is selected or deselected.
|
|
33075
|
+
* @param {THREE.Object3D|null} object
|
|
33076
|
+
*/
|
|
33077
|
+
}, {
|
|
33078
|
+
key: "onSelectionChanged",
|
|
33079
|
+
value: function onSelectionChanged(object) {
|
|
33080
|
+
var _object$userData;
|
|
33081
|
+
if (!object) {
|
|
33082
|
+
this.hide();
|
|
33083
|
+
return;
|
|
33084
|
+
}
|
|
33085
|
+
var objectType = (_object$userData = object.userData) === null || _object$userData === void 0 ? void 0 : _object$userData.objectType;
|
|
33086
|
+
if (objectType !== 'component') {
|
|
33087
|
+
this.hide();
|
|
33088
|
+
return;
|
|
33089
|
+
}
|
|
33090
|
+
this.selectedObject = object;
|
|
33091
|
+
this._ioExpanded = false;
|
|
33092
|
+
this._buildTooltip(object);
|
|
33093
|
+
}
|
|
33094
|
+
|
|
33095
|
+
/**
|
|
33096
|
+
* Update tooltip screen position. Call once per frame (from the animation loop).
|
|
33097
|
+
*/
|
|
33098
|
+
}, {
|
|
33099
|
+
key: "update",
|
|
33100
|
+
value: function update() {
|
|
33101
|
+
if (!this.tooltipEl || !this.selectedObject) return;
|
|
33102
|
+
this._positionTooltip();
|
|
33103
|
+
}
|
|
33104
|
+
|
|
33105
|
+
/**
|
|
33106
|
+
* Remove the tooltip from the DOM.
|
|
33107
|
+
*/
|
|
33108
|
+
}, {
|
|
33109
|
+
key: "hide",
|
|
33110
|
+
value: function hide() {
|
|
33111
|
+
if (this.tooltipEl) {
|
|
33112
|
+
this.tooltipEl.remove();
|
|
33113
|
+
this.tooltipEl = null;
|
|
33114
|
+
}
|
|
33115
|
+
this.selectedObject = null;
|
|
33116
|
+
this._ioExpanded = false;
|
|
33117
|
+
}
|
|
33118
|
+
|
|
33119
|
+
// -----------------------------------------------------------------------
|
|
33120
|
+
// Internal — build
|
|
33121
|
+
// -----------------------------------------------------------------------
|
|
33122
|
+
|
|
33123
|
+
/** Inject the stylesheet once into the document head */
|
|
33124
|
+
}, {
|
|
33125
|
+
key: "_injectStyles",
|
|
33126
|
+
value: function _injectStyles() {
|
|
33127
|
+
if (this._styleInjected) return;
|
|
33128
|
+
this._styleTag = document.createElement('style');
|
|
33129
|
+
this._styleTag.setAttribute('data-cp-tooltip', '');
|
|
33130
|
+
this._styleTag.textContent = TOOLTIP_STYLES;
|
|
33131
|
+
document.head.appendChild(this._styleTag);
|
|
33132
|
+
this._styleInjected = true;
|
|
33133
|
+
this.registerDOMElement(this._styleTag);
|
|
33134
|
+
}
|
|
33135
|
+
|
|
33136
|
+
/** Remove the injected stylesheet */
|
|
33137
|
+
}, {
|
|
33138
|
+
key: "_removeStyleTag",
|
|
33139
|
+
value: function _removeStyleTag() {
|
|
33140
|
+
if (this._styleTag && this._styleTag.parentNode) {
|
|
33141
|
+
this._styleTag.parentNode.removeChild(this._styleTag);
|
|
33142
|
+
}
|
|
33143
|
+
this._styleTag = null;
|
|
33144
|
+
this._styleInjected = false;
|
|
33145
|
+
}
|
|
33146
|
+
|
|
33147
|
+
/**
|
|
33148
|
+
* Gather I/O device children from a component's Three.js hierarchy.
|
|
33149
|
+
* @param {THREE.Object3D} object
|
|
33150
|
+
* @returns {{ label: string, deviceId: string }[]}
|
|
33151
|
+
*/
|
|
33152
|
+
}, {
|
|
33153
|
+
key: "_getIODevices",
|
|
33154
|
+
value: function _getIODevices(object) {
|
|
33155
|
+
var devices = [];
|
|
33156
|
+
object.traverse(function (child) {
|
|
33157
|
+
var _child$userData;
|
|
33158
|
+
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
|
|
33159
|
+
devices.push({
|
|
33160
|
+
label: child.userData.attachmentLabel || child.name || child.userData.deviceId || 'Unknown Device',
|
|
33161
|
+
deviceId: child.userData.deviceId || ''
|
|
33162
|
+
});
|
|
33163
|
+
}
|
|
33164
|
+
});
|
|
33165
|
+
return devices;
|
|
33166
|
+
}
|
|
33167
|
+
|
|
33168
|
+
/**
|
|
33169
|
+
* Build and show the tooltip for the given object.
|
|
33170
|
+
* @param {THREE.Object3D} object
|
|
33171
|
+
*/
|
|
33172
|
+
}, {
|
|
33173
|
+
key: "_buildTooltip",
|
|
33174
|
+
value: function _buildTooltip(object) {
|
|
33175
|
+
var _this2 = this;
|
|
33176
|
+
// Remove any existing tooltip first
|
|
33177
|
+
this.hide();
|
|
33178
|
+
// Re-assign selected object since hide() clears it
|
|
33179
|
+
this.selectedObject = object;
|
|
33180
|
+
var container = this._getContainer();
|
|
33181
|
+
if (!container) return;
|
|
33182
|
+
|
|
33183
|
+
// Ensure the container supports absolute positioning
|
|
33184
|
+
var containerStyle = window.getComputedStyle(container);
|
|
33185
|
+
if (containerStyle.position === 'static') {
|
|
33186
|
+
container.style.position = 'relative';
|
|
33187
|
+
}
|
|
33188
|
+
|
|
33189
|
+
// Gather data — extract the friendly name, stripping the " (component-id)" suffix
|
|
33190
|
+
var rawName = object.name || '';
|
|
33191
|
+
var componentName = rawName.replace(/\s*\([^)]*\)\s*$/, '') || 'Unnamed Component';
|
|
33192
|
+
var devices = this._getIODevices(object);
|
|
33193
|
+
var isSmart = devices.length > 0;
|
|
33194
|
+
|
|
33195
|
+
// Root element
|
|
33196
|
+
var root = document.createElement('div');
|
|
33197
|
+
root.className = 'cp-tooltip';
|
|
33198
|
+
|
|
33199
|
+
// Card
|
|
33200
|
+
var card = document.createElement('div');
|
|
33201
|
+
card.className = 'cp-tooltip__card';
|
|
33202
|
+
|
|
33203
|
+
// Header
|
|
33204
|
+
var header = document.createElement('div');
|
|
33205
|
+
header.className = 'cp-tooltip__header';
|
|
33206
|
+
header.textContent = componentName;
|
|
33207
|
+
card.appendChild(header);
|
|
33208
|
+
|
|
33209
|
+
// I/O Devices section
|
|
33210
|
+
if (isSmart) {
|
|
33211
|
+
var ioSection = document.createElement('div');
|
|
33212
|
+
ioSection.className = 'cp-tooltip__io-section';
|
|
33213
|
+
|
|
33214
|
+
// Trigger row
|
|
33215
|
+
var trigger = document.createElement('div');
|
|
33216
|
+
trigger.className = 'cp-tooltip__io-trigger';
|
|
33217
|
+
var label = document.createElement('span');
|
|
33218
|
+
label.className = 'cp-tooltip__io-trigger-label';
|
|
33219
|
+
label.textContent = "I/O Devices (".concat(devices.length, ")");
|
|
33220
|
+
var arrow = document.createElement('span');
|
|
33221
|
+
arrow.className = 'cp-tooltip__io-arrow';
|
|
33222
|
+
arrow.textContent = '▶';
|
|
33223
|
+
trigger.appendChild(label);
|
|
33224
|
+
trigger.appendChild(arrow);
|
|
33225
|
+
|
|
33226
|
+
// Device list
|
|
33227
|
+
var list = document.createElement('div');
|
|
33228
|
+
list.className = 'cp-tooltip__device-list';
|
|
33229
|
+
devices.forEach(function (device) {
|
|
33230
|
+
var item = document.createElement('div');
|
|
33231
|
+
item.className = 'cp-tooltip__device-item';
|
|
33232
|
+
var dot = document.createElement('span');
|
|
33233
|
+
dot.className = 'cp-tooltip__device-dot';
|
|
33234
|
+
var name = document.createElement('span');
|
|
33235
|
+
name.className = 'cp-tooltip__device-name';
|
|
33236
|
+
name.textContent = device.label;
|
|
33237
|
+
item.appendChild(dot);
|
|
33238
|
+
item.appendChild(name);
|
|
33239
|
+
list.appendChild(item);
|
|
33240
|
+
});
|
|
33241
|
+
ioSection.appendChild(trigger);
|
|
33242
|
+
ioSection.appendChild(list);
|
|
33243
|
+
|
|
33244
|
+
// Hover expand/collapse
|
|
33245
|
+
trigger.addEventListener('mouseenter', function () {
|
|
33246
|
+
ioSection.classList.add('expanded');
|
|
33247
|
+
_this2._ioExpanded = true;
|
|
33248
|
+
});
|
|
33249
|
+
ioSection.addEventListener('mouseleave', function () {
|
|
33250
|
+
ioSection.classList.remove('expanded');
|
|
33251
|
+
_this2._ioExpanded = false;
|
|
33252
|
+
});
|
|
33253
|
+
card.appendChild(ioSection);
|
|
33254
|
+
} else {
|
|
33255
|
+
// Non-smart: show empty state
|
|
33256
|
+
var noDevices = document.createElement('div');
|
|
33257
|
+
noDevices.className = 'cp-tooltip__no-devices';
|
|
33258
|
+
noDevices.textContent = 'No I/O devices attached';
|
|
33259
|
+
card.appendChild(noDevices);
|
|
33260
|
+
}
|
|
33261
|
+
root.appendChild(card);
|
|
33262
|
+
|
|
33263
|
+
// Caret
|
|
33264
|
+
var caret = document.createElement('div');
|
|
33265
|
+
caret.className = 'cp-tooltip__caret';
|
|
33266
|
+
root.appendChild(caret);
|
|
33267
|
+
|
|
33268
|
+
// Prevent clicks on tooltip from propagating to the scene
|
|
33269
|
+
root.addEventListener('pointerdown', function (e) {
|
|
33270
|
+
return e.stopPropagation();
|
|
33271
|
+
});
|
|
33272
|
+
root.addEventListener('click', function (e) {
|
|
33273
|
+
return e.stopPropagation();
|
|
33274
|
+
});
|
|
33275
|
+
|
|
33276
|
+
// Add to the renderer container so coordinates are relative to the viewport
|
|
33277
|
+
container.appendChild(root);
|
|
33278
|
+
this.tooltipEl = root;
|
|
33279
|
+
|
|
33280
|
+
// Initial positioning
|
|
33281
|
+
this._positionTooltip();
|
|
33282
|
+
}
|
|
33283
|
+
|
|
33284
|
+
// -----------------------------------------------------------------------
|
|
33285
|
+
// Internal — positioning
|
|
33286
|
+
// -----------------------------------------------------------------------
|
|
33287
|
+
|
|
33288
|
+
/**
|
|
33289
|
+
* Project the selected object's world position to screen space and
|
|
33290
|
+
* position the tooltip element accordingly.
|
|
33291
|
+
*/
|
|
33292
|
+
}, {
|
|
33293
|
+
key: "_positionTooltip",
|
|
33294
|
+
value: function _positionTooltip() {
|
|
33295
|
+
var _this$sceneViewer, _this$sceneViewer2;
|
|
33296
|
+
if (!this.tooltipEl || !this.selectedObject) return;
|
|
33297
|
+
var container = this._getContainer();
|
|
33298
|
+
var camera = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.camera;
|
|
33299
|
+
var renderer = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.renderer;
|
|
33300
|
+
if (!container || !camera || !renderer) return;
|
|
33301
|
+
|
|
33302
|
+
// Compute bounding box to position above the component
|
|
33303
|
+
var box = new THREE__namespace.Box3().setFromObject(this.selectedObject);
|
|
33304
|
+
var center = box.getCenter(new THREE__namespace.Vector3());
|
|
33305
|
+
// Use top of bounding box (Z-up)
|
|
33306
|
+
var topZ = box.max.z;
|
|
33307
|
+
var worldPos = new THREE__namespace.Vector3(center.x, center.y, topZ);
|
|
33308
|
+
|
|
33309
|
+
// Project to NDC
|
|
33310
|
+
var ndc = worldPos.clone().project(camera);
|
|
33311
|
+
|
|
33312
|
+
// NDC to pixel coords relative to the container
|
|
33313
|
+
var rect = container.getBoundingClientRect();
|
|
33314
|
+
var x = (ndc.x + 1) / 2 * rect.width;
|
|
33315
|
+
var y = (-ndc.y + 1) / 2 * rect.height;
|
|
33316
|
+
|
|
33317
|
+
// Hide if behind camera
|
|
33318
|
+
if (ndc.z > 1) {
|
|
33319
|
+
this.tooltipEl.style.display = 'none';
|
|
33320
|
+
return;
|
|
33321
|
+
}
|
|
33322
|
+
this.tooltipEl.style.display = '';
|
|
33323
|
+
this.tooltipEl.style.left = "".concat(x, "px");
|
|
33324
|
+
this.tooltipEl.style.top = "".concat(y, "px");
|
|
33325
|
+
}
|
|
33326
|
+
|
|
33327
|
+
/**
|
|
33328
|
+
* Get the DOM element where the Three.js canvas currently lives.
|
|
33329
|
+
* In QuadViewport the canvas is moved out of the original hidden
|
|
33330
|
+
* container, so we must use the renderer's actual parent element.
|
|
33331
|
+
* @returns {HTMLElement|null}
|
|
33332
|
+
*/
|
|
33333
|
+
}, {
|
|
33334
|
+
key: "_getContainer",
|
|
33335
|
+
value: function _getContainer() {
|
|
33336
|
+
var _this$sceneViewer3;
|
|
33337
|
+
return ((_this$sceneViewer3 = this.sceneViewer) === null || _this$sceneViewer3 === void 0 || (_this$sceneViewer3 = _this$sceneViewer3.renderer) === null || _this$sceneViewer3 === void 0 || (_this$sceneViewer3 = _this$sceneViewer3.domElement) === null || _this$sceneViewer3 === void 0 ? void 0 : _this$sceneViewer3.parentElement) || null;
|
|
33338
|
+
}
|
|
33339
|
+
}]);
|
|
33340
|
+
}(BaseDisposable);
|
|
33341
|
+
|
|
33083
33342
|
/**
|
|
33084
33343
|
* Viewport2DInstance
|
|
33085
33344
|
* Represents a single 2D viewport with its own Konva stage and configuration
|
|
@@ -34338,6 +34597,11 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
34338
34597
|
this.centralPlant.managers.tooltipsManager = new SceneTooltipsManager(this.centralPlant.sceneViewer.$refs.container, this.centralPlant.sceneViewer.camera, this.centralPlant.sceneViewer.scene);
|
|
34339
34598
|
this.centralPlant.sceneViewer.tooltipsManager = this.centralPlant.managers.tooltipsManager;
|
|
34340
34599
|
console.log('🔍 Tooltip manager initialized:', this.centralPlant.managers.tooltipsManager);
|
|
34600
|
+
|
|
34601
|
+
// Initialize the component tooltip manager (screen-space tooltip on selection)
|
|
34602
|
+
this.centralPlant.managers.componentTooltipManager = new ComponentTooltipManager(this.centralPlant.sceneViewer);
|
|
34603
|
+
this.centralPlant.sceneViewer.componentTooltipManager = this.centralPlant.managers.componentTooltipManager;
|
|
34604
|
+
console.log('🔍 Component tooltip manager initialized');
|
|
34341
34605
|
}
|
|
34342
34606
|
}
|
|
34343
34607
|
|
|
@@ -35088,8 +35352,21 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
35088
35352
|
// Clone the cached model to create a new instance
|
|
35089
35353
|
var componentModel = cachedModel;
|
|
35090
35354
|
|
|
35091
|
-
//
|
|
35092
|
-
|
|
35355
|
+
// Clone materials to isolate this component instance from the model cache.
|
|
35356
|
+
// Without this, shared materials would cause visual side-effects when one
|
|
35357
|
+
// component's material is modified (e.g., selection highlighting).
|
|
35358
|
+
componentModel.traverse(function (child) {
|
|
35359
|
+
if (child.isMesh && child.material) {
|
|
35360
|
+
if (Array.isArray(child.material)) {
|
|
35361
|
+
child.material = child.material.map(function (m) {
|
|
35362
|
+
return m.clone();
|
|
35363
|
+
});
|
|
35364
|
+
} else {
|
|
35365
|
+
child.material = child.material.clone();
|
|
35366
|
+
}
|
|
35367
|
+
}
|
|
35368
|
+
});
|
|
35369
|
+
|
|
35093
35370
|
// Set the component properties
|
|
35094
35371
|
componentModel.uuid = componentId;
|
|
35095
35372
|
|
|
@@ -35446,7 +35723,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
35446
35723
|
* Initialize the CentralPlant manager
|
|
35447
35724
|
*
|
|
35448
35725
|
* @constructor
|
|
35449
|
-
* @version 0.1.
|
|
35726
|
+
* @version 0.1.80
|
|
35450
35727
|
* @updated 2025-10-22
|
|
35451
35728
|
*
|
|
35452
35729
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -37714,7 +37991,7 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37714
37991
|
this.centralPlant.attachToComponent();
|
|
37715
37992
|
|
|
37716
37993
|
// Sync our managers tracking object after attachment
|
|
37717
|
-
managerKeys = ['threeJSResourceManager', 'performanceMonitorManager', 'settingsManager', 'sceneExportManager', 'componentManager', 'sceneInitializationManager', 'environmentManager', 'keyboardControlsManager', 'pathfindingManager', 'sceneOperationsManager', 'animationManager', 'cameraControlsManager', 'componentDragManager', 'tooltipsManager']; // Populate our managers tracking object
|
|
37994
|
+
managerKeys = ['threeJSResourceManager', 'performanceMonitorManager', 'settingsManager', 'sceneExportManager', 'componentManager', 'sceneInitializationManager', 'environmentManager', 'keyboardControlsManager', 'pathfindingManager', 'sceneOperationsManager', 'animationManager', 'cameraControlsManager', 'componentDragManager', 'tooltipsManager', 'componentTooltipManager']; // Populate our managers tracking object
|
|
37718
37995
|
managerKeys.forEach(function (key) {
|
|
37719
37996
|
if (_this2[key]) {
|
|
37720
37997
|
_this2.managers[key] = _this2[key];
|
|
@@ -37992,6 +38269,10 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37992
38269
|
this.transformManager.on({
|
|
37993
38270
|
onModeChange: this.onModeChange.bind(this),
|
|
37994
38271
|
onSelectionChanged: function onSelectionChanged(object) {
|
|
38272
|
+
// Update the component tooltip on selection changes
|
|
38273
|
+
if (_this4.componentTooltipManager) {
|
|
38274
|
+
_this4.componentTooltipManager.onSelectionChanged(object);
|
|
38275
|
+
}
|
|
37995
38276
|
if (object) {
|
|
37996
38277
|
var _object$userData;
|
|
37997
38278
|
// Object selected
|
|
@@ -38417,6 +38698,12 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
38417
38698
|
this.tooltipsManager = null;
|
|
38418
38699
|
}
|
|
38419
38700
|
|
|
38701
|
+
// Clean up component tooltip manager
|
|
38702
|
+
if (this.componentTooltipManager) {
|
|
38703
|
+
this.componentTooltipManager.dispose('ComponentTooltipManager');
|
|
38704
|
+
this.componentTooltipManager = null;
|
|
38705
|
+
}
|
|
38706
|
+
|
|
38420
38707
|
// Fallback cleanup if Three.js resource manager not available
|
|
38421
38708
|
if (!this.threeJSResourceManager) {
|
|
38422
38709
|
// Fallback cleanup if disposal manager not available
|
|
@@ -41044,6 +41331,19 @@ var Rendering3D = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
41044
41331
|
this.renderer.useLegacyLights = false;
|
|
41045
41332
|
container.appendChild(this.renderer.domElement);
|
|
41046
41333
|
|
|
41334
|
+
// Register WebGL context lost/restored handlers for resilience.
|
|
41335
|
+
// If the GPU context is lost (e.g., due to disposed buffers or driver issues),
|
|
41336
|
+
// these handlers prevent a permanent white screen.
|
|
41337
|
+
this._onContextLost = function (event) {
|
|
41338
|
+
event.preventDefault();
|
|
41339
|
+
console.warn('⚠️ WebGL context lost — rendering paused. The browser may restore it automatically.');
|
|
41340
|
+
};
|
|
41341
|
+
this._onContextRestored = function () {
|
|
41342
|
+
console.log('✅ WebGL context restored — rendering will resume.');
|
|
41343
|
+
};
|
|
41344
|
+
this.renderer.domElement.addEventListener('webglcontextlost', this._onContextLost, false);
|
|
41345
|
+
this.renderer.domElement.addEventListener('webglcontextrestored', this._onContextRestored, false);
|
|
41346
|
+
|
|
41047
41347
|
// Register resources for automatic cleanup
|
|
41048
41348
|
this.registerDOMElement(this.renderer.domElement);
|
|
41049
41349
|
this.registerDisposable(this.renderer, 'WebGLRenderer');
|
|
@@ -41254,6 +41554,18 @@ var Rendering3D = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
41254
41554
|
frameTime: 0
|
|
41255
41555
|
};
|
|
41256
41556
|
|
|
41557
|
+
// Remove WebGL context event listeners
|
|
41558
|
+
if (this.renderer && this.renderer.domElement) {
|
|
41559
|
+
if (this._onContextLost) {
|
|
41560
|
+
this.renderer.domElement.removeEventListener('webglcontextlost', this._onContextLost, false);
|
|
41561
|
+
}
|
|
41562
|
+
if (this._onContextRestored) {
|
|
41563
|
+
this.renderer.domElement.removeEventListener('webglcontextrestored', this._onContextRestored, false);
|
|
41564
|
+
}
|
|
41565
|
+
}
|
|
41566
|
+
this._onContextLost = null;
|
|
41567
|
+
this._onContextRestored = null;
|
|
41568
|
+
|
|
41257
41569
|
// Clear post processing
|
|
41258
41570
|
this.postProcessing = {
|
|
41259
41571
|
composer: null,
|
|
@@ -41278,6 +41590,7 @@ exports.CentralPlant = CentralPlant;
|
|
|
41278
41590
|
exports.ComponentDataManager = ComponentDataManager;
|
|
41279
41591
|
exports.ComponentDragManager = ComponentDragManager;
|
|
41280
41592
|
exports.ComponentManager = ComponentManager;
|
|
41593
|
+
exports.ComponentTooltipManager = ComponentTooltipManager;
|
|
41281
41594
|
exports.EnvironmentManager = EnvironmentManager;
|
|
41282
41595
|
exports.KeyboardControlsManager = KeyboardControlsManager;
|
|
41283
41596
|
exports.ModelManager = ModelManager;
|