@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.
@@ -1,6 +1,8 @@
1
- import { asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, objectSpread2 as _objectSpread2, construct as _construct, toConsumableArray as _toConsumableArray, slicedToArray as _slicedToArray } from '../../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, construct as _construct, toConsumableArray as _toConsumableArray } from '../../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import * as THREE from 'three';
3
3
 
4
+ /** Maximum anisotropy to apply (caps GPU memory for mip storage) */
5
+ var MAX_ANISOTROPY = 4;
4
6
  var TEXTURE_SETS = {
5
7
  // Light metallic texture using the gravel_embedded_concrete with metallic properties
6
8
  light_metal: {
@@ -137,10 +139,29 @@ function _loadTextureSet() {
137
139
  return Promise.all(promises);
138
140
  case 2:
139
141
  loadedTextures = _context2.v;
140
- textureMap = Object.fromEntries(loadedTextures); // Apply texture settings
141
- Object.values(textureMap).forEach(function (texture) {
142
+ textureMap = Object.fromEntries(loadedTextures); // Apply texture settings with memory-conscious defaults
143
+ Object.entries(textureMap).forEach(function (_ref4) {
144
+ var _ref5 = _slicedToArray(_ref4, 2),
145
+ type = _ref5[0],
146
+ texture = _ref5[1];
142
147
  texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
143
148
  texture.repeat.set(textureSet.repeat.x, textureSet.repeat.y);
149
+
150
+ // Correct colour-space: diffuse is sRGB, everything else is linear data
151
+ if (type === 'diffuse') {
152
+ texture.colorSpace = THREE.SRGBColorSpace;
153
+ } else {
154
+ texture.colorSpace = THREE.LinearSRGBColorSpace;
155
+ }
156
+
157
+ // Roughness maps don't benefit much from mipmaps — skip them to save GPU memory
158
+ if (type === 'roughness') {
159
+ texture.generateMipmaps = false;
160
+ texture.minFilter = THREE.LinearFilter;
161
+ }
162
+
163
+ // Cap anisotropy to balance quality vs memory
164
+ texture.anisotropy = MAX_ANISOTROPY;
144
165
  });
145
166
  console.log("Texture set ".concat(setName, " loaded successfully"));
146
167
  return _context2.a(2, {
@@ -58,18 +58,32 @@ var AnimationManager = /*#__PURE__*/function (_BaseDisposable) {
58
58
  if (sceneViewer.performanceMonitorManager) {
59
59
  sceneViewer.performanceMonitorManager.beginFrame();
60
60
  }
61
-
62
- // Update controls
63
- sceneViewer.controls.update();
64
-
65
- // Render the scene
66
- sceneViewer.renderer.render(sceneViewer.scene, sceneViewer.camera);
61
+ try {
62
+ // Update controls
63
+ sceneViewer.controls.update();
64
+
65
+ // Render the scene
66
+ sceneViewer.renderer.render(sceneViewer.scene, sceneViewer.camera);
67
+ } catch (renderError) {
68
+ // Catch WebGL or rendering errors to prevent the animation loop from
69
+ // producing a permanent white screen. Log once and continue so that
70
+ // subsequent frames can recover if the problematic object is removed.
71
+ if (!this._hasLoggedRenderError) {
72
+ console.error('❌ AnimationManager: Render error caught — scene may contain disposed resources:', renderError);
73
+ this._hasLoggedRenderError = true;
74
+ }
75
+ }
67
76
 
68
77
  // Render tooltips if tooltipsManager exists
69
78
  if (sceneViewer.tooltipsManager) {
70
79
  sceneViewer.tooltipsManager.render();
71
80
  }
72
81
 
82
+ // Update component tooltip screen position
83
+ if (sceneViewer.componentTooltipManager) {
84
+ sceneViewer.componentTooltipManager.update();
85
+ }
86
+
73
87
  // End performance monitoring frame
74
88
  if (sceneViewer.performanceMonitorManager) {
75
89
  sceneViewer.performanceMonitorManager.endFrame();
@@ -0,0 +1,316 @@
1
+ import { inherits as _inherits, createClass as _createClass, classCallCheck as _classCallCheck, callSuper as _callSuper } from '../../../_virtual/_rollupPluginBabelHelpers.js';
2
+ import * as THREE from 'three';
3
+ import { BaseDisposable } from '../../core/baseDisposable.js';
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Inline styles (injected once into the document head)
7
+ // ---------------------------------------------------------------------------
8
+ 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";
9
+ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
10
+ /**
11
+ * @param {Object} sceneViewer - The sceneViewer instance
12
+ */
13
+ function ComponentTooltipManager(sceneViewer) {
14
+ var _this;
15
+ _classCallCheck(this, ComponentTooltipManager);
16
+ _this = _callSuper(this, ComponentTooltipManager);
17
+ _this.sceneViewer = sceneViewer;
18
+ _this.selectedObject = null;
19
+ _this.tooltipEl = null;
20
+ _this._styleInjected = false;
21
+ _this._ioExpanded = false;
22
+ _this._injectStyles();
23
+ return _this;
24
+ }
25
+
26
+ // -----------------------------------------------------------------------
27
+ // Lifecycle
28
+ // -----------------------------------------------------------------------
29
+
30
+ /**
31
+ * Called automatically by BaseDisposable.dispose()
32
+ * @override
33
+ */
34
+ _inherits(ComponentTooltipManager, _BaseDisposable);
35
+ return _createClass(ComponentTooltipManager, [{
36
+ key: "_doDispose",
37
+ value: function _doDispose() {
38
+ this.hide();
39
+ this._removeStyleTag();
40
+ this.nullifyProperties('sceneViewer', 'selectedObject', 'tooltipEl');
41
+ }
42
+
43
+ // -----------------------------------------------------------------------
44
+ // Public API
45
+ // -----------------------------------------------------------------------
46
+
47
+ /**
48
+ * Should be called when an object is selected or deselected.
49
+ * @param {THREE.Object3D|null} object
50
+ */
51
+ }, {
52
+ key: "onSelectionChanged",
53
+ value: function onSelectionChanged(object) {
54
+ var _object$userData;
55
+ if (!object) {
56
+ this.hide();
57
+ return;
58
+ }
59
+ var objectType = (_object$userData = object.userData) === null || _object$userData === void 0 ? void 0 : _object$userData.objectType;
60
+ if (objectType !== 'component') {
61
+ this.hide();
62
+ return;
63
+ }
64
+ this.selectedObject = object;
65
+ this._ioExpanded = false;
66
+ this._buildTooltip(object);
67
+ }
68
+
69
+ /**
70
+ * Update tooltip screen position. Call once per frame (from the animation loop).
71
+ */
72
+ }, {
73
+ key: "update",
74
+ value: function update() {
75
+ if (!this.tooltipEl || !this.selectedObject) return;
76
+ this._positionTooltip();
77
+ }
78
+
79
+ /**
80
+ * Remove the tooltip from the DOM.
81
+ */
82
+ }, {
83
+ key: "hide",
84
+ value: function hide() {
85
+ if (this.tooltipEl) {
86
+ this.tooltipEl.remove();
87
+ this.tooltipEl = null;
88
+ }
89
+ this.selectedObject = null;
90
+ this._ioExpanded = false;
91
+ }
92
+
93
+ // -----------------------------------------------------------------------
94
+ // Internal — build
95
+ // -----------------------------------------------------------------------
96
+
97
+ /** Inject the stylesheet once into the document head */
98
+ }, {
99
+ key: "_injectStyles",
100
+ value: function _injectStyles() {
101
+ if (this._styleInjected) return;
102
+ this._styleTag = document.createElement('style');
103
+ this._styleTag.setAttribute('data-cp-tooltip', '');
104
+ this._styleTag.textContent = TOOLTIP_STYLES;
105
+ document.head.appendChild(this._styleTag);
106
+ this._styleInjected = true;
107
+ this.registerDOMElement(this._styleTag);
108
+ }
109
+
110
+ /** Remove the injected stylesheet */
111
+ }, {
112
+ key: "_removeStyleTag",
113
+ value: function _removeStyleTag() {
114
+ if (this._styleTag && this._styleTag.parentNode) {
115
+ this._styleTag.parentNode.removeChild(this._styleTag);
116
+ }
117
+ this._styleTag = null;
118
+ this._styleInjected = false;
119
+ }
120
+
121
+ /**
122
+ * Gather I/O device children from a component's Three.js hierarchy.
123
+ * @param {THREE.Object3D} object
124
+ * @returns {{ label: string, deviceId: string }[]}
125
+ */
126
+ }, {
127
+ key: "_getIODevices",
128
+ value: function _getIODevices(object) {
129
+ var devices = [];
130
+ object.traverse(function (child) {
131
+ var _child$userData;
132
+ if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
133
+ devices.push({
134
+ label: child.userData.attachmentLabel || child.name || child.userData.deviceId || 'Unknown Device',
135
+ deviceId: child.userData.deviceId || ''
136
+ });
137
+ }
138
+ });
139
+ return devices;
140
+ }
141
+
142
+ /**
143
+ * Build and show the tooltip for the given object.
144
+ * @param {THREE.Object3D} object
145
+ */
146
+ }, {
147
+ key: "_buildTooltip",
148
+ value: function _buildTooltip(object) {
149
+ var _this2 = this;
150
+ // Remove any existing tooltip first
151
+ this.hide();
152
+ // Re-assign selected object since hide() clears it
153
+ this.selectedObject = object;
154
+ var container = this._getContainer();
155
+ if (!container) return;
156
+
157
+ // Ensure the container supports absolute positioning
158
+ var containerStyle = window.getComputedStyle(container);
159
+ if (containerStyle.position === 'static') {
160
+ container.style.position = 'relative';
161
+ }
162
+
163
+ // Gather data — extract the friendly name, stripping the " (component-id)" suffix
164
+ var rawName = object.name || '';
165
+ var componentName = rawName.replace(/\s*\([^)]*\)\s*$/, '') || 'Unnamed Component';
166
+ var devices = this._getIODevices(object);
167
+ var isSmart = devices.length > 0;
168
+
169
+ // Root element
170
+ var root = document.createElement('div');
171
+ root.className = 'cp-tooltip';
172
+
173
+ // Card
174
+ var card = document.createElement('div');
175
+ card.className = 'cp-tooltip__card';
176
+
177
+ // Header
178
+ var header = document.createElement('div');
179
+ header.className = 'cp-tooltip__header';
180
+ header.textContent = componentName;
181
+ card.appendChild(header);
182
+
183
+ // I/O Devices section
184
+ if (isSmart) {
185
+ var ioSection = document.createElement('div');
186
+ ioSection.className = 'cp-tooltip__io-section';
187
+
188
+ // Trigger row
189
+ var trigger = document.createElement('div');
190
+ trigger.className = 'cp-tooltip__io-trigger';
191
+ var label = document.createElement('span');
192
+ label.className = 'cp-tooltip__io-trigger-label';
193
+ label.textContent = "I/O Devices (".concat(devices.length, ")");
194
+ var arrow = document.createElement('span');
195
+ arrow.className = 'cp-tooltip__io-arrow';
196
+ arrow.textContent = '▶';
197
+ trigger.appendChild(label);
198
+ trigger.appendChild(arrow);
199
+
200
+ // Device list
201
+ var list = document.createElement('div');
202
+ list.className = 'cp-tooltip__device-list';
203
+ devices.forEach(function (device) {
204
+ var item = document.createElement('div');
205
+ item.className = 'cp-tooltip__device-item';
206
+ var dot = document.createElement('span');
207
+ dot.className = 'cp-tooltip__device-dot';
208
+ var name = document.createElement('span');
209
+ name.className = 'cp-tooltip__device-name';
210
+ name.textContent = device.label;
211
+ item.appendChild(dot);
212
+ item.appendChild(name);
213
+ list.appendChild(item);
214
+ });
215
+ ioSection.appendChild(trigger);
216
+ ioSection.appendChild(list);
217
+
218
+ // Hover expand/collapse
219
+ trigger.addEventListener('mouseenter', function () {
220
+ ioSection.classList.add('expanded');
221
+ _this2._ioExpanded = true;
222
+ });
223
+ ioSection.addEventListener('mouseleave', function () {
224
+ ioSection.classList.remove('expanded');
225
+ _this2._ioExpanded = false;
226
+ });
227
+ card.appendChild(ioSection);
228
+ } else {
229
+ // Non-smart: show empty state
230
+ var noDevices = document.createElement('div');
231
+ noDevices.className = 'cp-tooltip__no-devices';
232
+ noDevices.textContent = 'No I/O devices attached';
233
+ card.appendChild(noDevices);
234
+ }
235
+ root.appendChild(card);
236
+
237
+ // Caret
238
+ var caret = document.createElement('div');
239
+ caret.className = 'cp-tooltip__caret';
240
+ root.appendChild(caret);
241
+
242
+ // Prevent clicks on tooltip from propagating to the scene
243
+ root.addEventListener('pointerdown', function (e) {
244
+ return e.stopPropagation();
245
+ });
246
+ root.addEventListener('click', function (e) {
247
+ return e.stopPropagation();
248
+ });
249
+
250
+ // Add to the renderer container so coordinates are relative to the viewport
251
+ container.appendChild(root);
252
+ this.tooltipEl = root;
253
+
254
+ // Initial positioning
255
+ this._positionTooltip();
256
+ }
257
+
258
+ // -----------------------------------------------------------------------
259
+ // Internal — positioning
260
+ // -----------------------------------------------------------------------
261
+
262
+ /**
263
+ * Project the selected object's world position to screen space and
264
+ * position the tooltip element accordingly.
265
+ */
266
+ }, {
267
+ key: "_positionTooltip",
268
+ value: function _positionTooltip() {
269
+ var _this$sceneViewer, _this$sceneViewer2;
270
+ if (!this.tooltipEl || !this.selectedObject) return;
271
+ var container = this._getContainer();
272
+ var camera = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.camera;
273
+ var renderer = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.renderer;
274
+ if (!container || !camera || !renderer) return;
275
+
276
+ // Compute bounding box to position above the component
277
+ var box = new THREE.Box3().setFromObject(this.selectedObject);
278
+ var center = box.getCenter(new THREE.Vector3());
279
+ // Use top of bounding box (Z-up)
280
+ var topZ = box.max.z;
281
+ var worldPos = new THREE.Vector3(center.x, center.y, topZ);
282
+
283
+ // Project to NDC
284
+ var ndc = worldPos.clone().project(camera);
285
+
286
+ // NDC to pixel coords relative to the container
287
+ var rect = container.getBoundingClientRect();
288
+ var x = (ndc.x + 1) / 2 * rect.width;
289
+ var y = (-ndc.y + 1) / 2 * rect.height;
290
+
291
+ // Hide if behind camera
292
+ if (ndc.z > 1) {
293
+ this.tooltipEl.style.display = 'none';
294
+ return;
295
+ }
296
+ this.tooltipEl.style.display = '';
297
+ this.tooltipEl.style.left = "".concat(x, "px");
298
+ this.tooltipEl.style.top = "".concat(y, "px");
299
+ }
300
+
301
+ /**
302
+ * Get the DOM element where the Three.js canvas currently lives.
303
+ * In QuadViewport the canvas is moved out of the original hidden
304
+ * container, so we must use the renderer's actual parent element.
305
+ * @returns {HTMLElement|null}
306
+ */
307
+ }, {
308
+ key: "_getContainer",
309
+ value: function _getContainer() {
310
+ var _this$sceneViewer3;
311
+ 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;
312
+ }
313
+ }]);
314
+ }(BaseDisposable);
315
+
316
+ export { ComponentTooltipManager };
@@ -456,6 +456,19 @@ var Rendering3D = /*#__PURE__*/function (_BaseDisposable) {
456
456
  this.renderer.useLegacyLights = false;
457
457
  container.appendChild(this.renderer.domElement);
458
458
 
459
+ // Register WebGL context lost/restored handlers for resilience.
460
+ // If the GPU context is lost (e.g., due to disposed buffers or driver issues),
461
+ // these handlers prevent a permanent white screen.
462
+ this._onContextLost = function (event) {
463
+ event.preventDefault();
464
+ console.warn('⚠️ WebGL context lost — rendering paused. The browser may restore it automatically.');
465
+ };
466
+ this._onContextRestored = function () {
467
+ console.log('✅ WebGL context restored — rendering will resume.');
468
+ };
469
+ this.renderer.domElement.addEventListener('webglcontextlost', this._onContextLost, false);
470
+ this.renderer.domElement.addEventListener('webglcontextrestored', this._onContextRestored, false);
471
+
459
472
  // Register resources for automatic cleanup
460
473
  this.registerDOMElement(this.renderer.domElement);
461
474
  this.registerDisposable(this.renderer, 'WebGLRenderer');
@@ -666,6 +679,18 @@ var Rendering3D = /*#__PURE__*/function (_BaseDisposable) {
666
679
  frameTime: 0
667
680
  };
668
681
 
682
+ // Remove WebGL context event listeners
683
+ if (this.renderer && this.renderer.domElement) {
684
+ if (this._onContextLost) {
685
+ this.renderer.domElement.removeEventListener('webglcontextlost', this._onContextLost, false);
686
+ }
687
+ if (this._onContextRestored) {
688
+ this.renderer.domElement.removeEventListener('webglcontextrestored', this._onContextRestored, false);
689
+ }
690
+ }
691
+ this._onContextLost = null;
692
+ this._onContextRestored = null;
693
+
669
694
  // Clear post processing
670
695
  this.postProcessing = {
671
696
  composer: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2112-lab/central-plant",
3
- "version": "0.1.78",
3
+ "version": "0.1.80",
4
4
  "description": "Utility modules for the Central Plant Application",
5
5
  "main": "dist/bundle/index.js",
6
6
  "module": "dist/esm/index.js",