@xviewer.js/debug 1.0.4-alpha.0 → 1.0.4-alpha.10

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/main.cjs CHANGED
@@ -1,11 +1,32 @@
1
1
  'use strict';
2
2
 
3
3
  var three = require('three');
4
+ var Addons = require('three/examples/jsm/Addons');
5
+ var TextureUtils = require('three/examples/jsm/utils/WebGLTextureUtils');
4
6
  var core = require('@xviewer.js/core');
5
7
 
6
- var e=[],t=[];function n(n,r){if(n&&"undefined"!=typeof document){var a,s=!0===r.prepend?"prepend":"append",d=!0===r.singleTag,i="string"==typeof r.container?document.querySelector(r.container):document.getElementsByTagName("head")[0];if(d){var u=e.indexOf(i);-1===u&&(u=e.push(i)-1,t[u]={}),a=t[u]&&t[u][s]?t[u][s]:t[u][s]=c();}else a=c();65279===n.charCodeAt(0)&&(n=n.substring(1)),a.styleSheet?a.styleSheet.cssText+=n:a.appendChild(document.createTextNode(n));}function c(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),r.attributes)for(var t=Object.keys(r.attributes),n=0;n<t.length;n++)e.setAttribute(t[n],r.attributes[t[n]]);var a="prepend"===s?"afterbegin":"beforeend";return i.insertAdjacentElement(a,e),e}}
8
+ function _interopNamespaceDefault(e) {
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n.default = e;
22
+ return Object.freeze(n);
23
+ }
7
24
 
8
- var css = "@charset \"UTF-8\";\n.lil-gui {\n font-family: var(--font-family);\n font-size: var(--font-size);\n line-height: 1;\n font-weight: normal;\n font-style: normal;\n text-align: left;\n background-color: var(--background-color);\n color: var(--text-color);\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n --background-color: #1f1f1f;\n --text-color: #ebebeb;\n --title-background-color: #111111;\n --title-text-color: #ebebeb;\n --widget-color: #424242;\n --hover-color: #4f4f4f;\n --focus-color: #595959;\n --number-color: #2cc9ff;\n --string-color: #a2db3c;\n --font-size: 11px;\n --input-font-size: 11px;\n --font-family: -apple-system,\n BlinkMacSystemFont,\n \"Segoe UI\",\n Roboto,\n Arial,\n sans-serif;\n --font-family-mono: Menlo,\n Monaco,\n Consolas,\n \"Droid Sans Mono\",\n monospace;\n --padding: 4px;\n --spacing: 4px;\n --widget-height: 20px;\n --title-height: calc(var(--widget-height) + var(--spacing) * 1.25);\n --name-width: 40%;\n --slider-knob-width: 2px;\n --slider-input-width: 27%;\n --color-input-width: 27%;\n --slider-input-min-width: 45px;\n --color-input-min-width: 45px;\n --folder-indent: 7px;\n --widget-padding: 0 0 0 3px;\n --widget-border-radius: 2px;\n --checkbox-size: calc(0.75 * var(--widget-height));\n --scrollbar-width: 5px;\n}\n.lil-gui, .lil-gui * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n.lil-gui.root {\n width: var(--width, 245px);\n display: flex;\n flex-direction: column;\n}\n.lil-gui.root > .title {\n background: var(--title-background-color);\n color: var(--title-text-color);\n}\n.lil-gui.root > .children {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.lil-gui.root > .children::-webkit-scrollbar {\n width: var(--scrollbar-width);\n height: var(--scrollbar-width);\n background: var(--background-color);\n}\n.lil-gui.root > .children::-webkit-scrollbar-thumb {\n border-radius: var(--scrollbar-width);\n background: var(--focus-color);\n}\n@media (pointer: coarse) {\n .lil-gui.allow-touch-styles, .lil-gui.allow-touch-styles .lil-gui {\n --widget-height: 28px;\n --padding: 6px;\n --spacing: 6px;\n --font-size: 13px;\n --input-font-size: 16px;\n --folder-indent: 10px;\n --scrollbar-width: 7px;\n --slider-input-min-width: 50px;\n --color-input-min-width: 65px;\n }\n}\n.lil-gui.force-touch-styles, .lil-gui.force-touch-styles .lil-gui {\n --widget-height: 28px;\n --padding: 6px;\n --spacing: 6px;\n --font-size: 13px;\n --input-font-size: 16px;\n --folder-indent: 10px;\n --scrollbar-width: 7px;\n --slider-input-min-width: 50px;\n --color-input-min-width: 65px;\n}\n.lil-gui.autoPlace {\n max-height: 100%;\n position: fixed;\n top: 0;\n right: 15px;\n z-index: 1001;\n}\n\n.lil-gui .controller {\n display: flex;\n align-items: center;\n padding: 0 var(--padding);\n margin: var(--spacing) 0;\n}\n.lil-gui .controller.disabled {\n opacity: 0.5;\n}\n.lil-gui .controller.disabled, .lil-gui .controller.disabled * {\n pointer-events: none !important;\n}\n.lil-gui .controller > .name {\n min-width: var(--name-width);\n flex-shrink: 0;\n white-space: pre;\n padding-right: var(--spacing);\n line-height: var(--widget-height);\n}\n.lil-gui .controller .widget {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-height: var(--widget-height);\n}\n.lil-gui .controller.string input {\n color: var(--string-color);\n}\n.lil-gui .controller.boolean .widget {\n cursor: pointer;\n}\n.lil-gui .controller.color .display {\n width: 100%;\n height: var(--widget-height);\n border-radius: var(--widget-border-radius);\n position: relative;\n}\n@media (hover: hover) {\n .lil-gui .controller.color .display:hover:before {\n content: \" \";\n display: block;\n position: absolute;\n border-radius: var(--widget-border-radius);\n border: 1px solid rgba(255, 255, 255, 0.6);\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n}\n.lil-gui .controller.color input[type=color] {\n opacity: 0;\n width: 100%;\n height: 100%;\n cursor: pointer;\n}\n.lil-gui .controller.color input[type=text] {\n margin-left: var(--spacing);\n font-family: var(--font-family-mono);\n min-width: var(--color-input-min-width);\n width: var(--color-input-width);\n flex-shrink: 0;\n}\n.lil-gui .controller.option select {\n opacity: 0;\n position: absolute;\n width: 100%;\n max-width: 100%;\n}\n.lil-gui .controller.option .display {\n position: relative;\n pointer-events: none;\n border-radius: var(--widget-border-radius);\n height: var(--widget-height);\n line-height: var(--widget-height);\n max-width: 100%;\n overflow: hidden;\n word-break: break-all;\n padding-left: 0.55em;\n padding-right: 1.75em;\n background: var(--widget-color);\n}\n@media (hover: hover) {\n .lil-gui .controller.option .display.focus {\n background: var(--focus-color);\n }\n}\n.lil-gui .controller.option .display.active {\n background: var(--focus-color);\n}\n.lil-gui .controller.option .display:after {\n font-family: \"lil-gui\";\n content: \"↕\";\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n padding-right: 0.375em;\n}\n.lil-gui .controller.option .widget,\n.lil-gui .controller.option select {\n cursor: pointer;\n}\n@media (hover: hover) {\n .lil-gui .controller.option .widget:hover .display {\n background: var(--hover-color);\n }\n}\n.lil-gui .controller.number input {\n color: var(--number-color);\n}\n.lil-gui .controller.number.hasSlider input {\n margin-left: var(--spacing);\n width: var(--slider-input-width);\n min-width: var(--slider-input-min-width);\n flex-shrink: 0;\n}\n.lil-gui .controller.number .slider {\n width: 100%;\n height: var(--widget-height);\n background-color: var(--widget-color);\n border-radius: var(--widget-border-radius);\n padding-right: var(--slider-knob-width);\n overflow: hidden;\n cursor: ew-resize;\n touch-action: pan-y;\n}\n@media (hover: hover) {\n .lil-gui .controller.number .slider:hover {\n background-color: var(--hover-color);\n }\n}\n.lil-gui .controller.number .slider.active {\n background-color: var(--focus-color);\n}\n.lil-gui .controller.number .slider.active .fill {\n opacity: 0.95;\n}\n.lil-gui .controller.number .fill {\n height: 100%;\n border-right: var(--slider-knob-width) solid var(--number-color);\n box-sizing: content-box;\n}\n.lil-gui .controller.texture canvas {\n width: 100%;\n border-radius: var(--widget-border-radius);\n}\n.lil-gui .controller.texture .group {\n display: flex;\n position: relative;\n width: 100%;\n}\n.lil-gui .controller.texture .info {\n position: absolute;\n display: flex;\n gap: 11px;\n}\n.lil-gui .controller.texture .label {\n position: absolute;\n background-color: rgba(0, 0, 0, 0.6745098039);\n display: \"flex\";\n padding: 2px;\n border-radius: var(--widget-border-radius);\n}\n.lil-gui .controller.texture .block {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n margin-top: 2px;\n width: var(--font-size);\n height: var(--font-size);\n border-radius: var(--font-size);\n background-color: white;\n cursor: pointer;\n}\n.lil-gui .controller.texture .block.select {\n background-color: var(--string-color);\n}\n.lil-gui .controller.image img {\n width: 100%;\n}\n.lil-gui .controller.image canvas {\n width: 100%;\n}\n.lil-gui .controller.vector input {\n color: var(--number-color);\n}\n.lil-gui .controller.vector .fill {\n height: 100%;\n margin-left: var(--spacing);\n box-sizing: content-box;\n}\n\n.lil-gui-dragging .lil-gui {\n --hover-color: var(--widget-color);\n}\n.lil-gui-dragging * {\n cursor: ew-resize !important;\n}\n\n.lil-gui-dragging.lil-gui-vertical * {\n cursor: ns-resize !important;\n}\n\n.lil-gui .title {\n height: var(--title-height);\n line-height: calc(var(--title-height) - 4px);\n font-weight: 600;\n padding: 0 var(--padding);\n -webkit-tap-highlight-color: transparent;\n cursor: pointer;\n outline: none;\n text-decoration-skip: objects;\n}\n.lil-gui .title:before {\n font-family: \"lil-gui\";\n content: \"▾\";\n padding-right: 2px;\n display: inline-block;\n}\n.lil-gui .title:active {\n background: var(--title-background-color);\n opacity: 0.75;\n}\n@media (hover: hover) {\n body:not(.lil-gui-dragging) .lil-gui .title:hover {\n background: var(--title-background-color);\n opacity: 0.85;\n }\n .lil-gui .title:focus {\n text-decoration: underline var(--focus-color);\n }\n}\n.lil-gui.root > .title:focus {\n text-decoration: none !important;\n}\n.lil-gui.closed > .title:before {\n content: \"▸\";\n}\n.lil-gui.closed > .children {\n transform: translateY(-7px);\n opacity: 0;\n}\n.lil-gui.closed:not(.transition) > .children {\n display: none;\n}\n.lil-gui.transition > .children {\n transition-duration: 300ms;\n transition-property: height, opacity, transform;\n transition-timing-function: cubic-bezier(0.2, 0.6, 0.35, 1);\n overflow: hidden;\n pointer-events: none;\n}\n.lil-gui .children:empty:before {\n content: \"Empty\";\n padding: 0 var(--padding);\n margin: var(--spacing) 0;\n display: block;\n height: var(--widget-height);\n font-style: italic;\n line-height: var(--widget-height);\n opacity: 0.5;\n}\n.lil-gui.root > .children > .lil-gui > .title {\n border: 0 solid var(--widget-color);\n border-width: 1px 0;\n transition: border-color 300ms;\n}\n.lil-gui.root > .children > .lil-gui.closed > .title {\n border-bottom-color: transparent;\n}\n.lil-gui + .controller {\n border-top: 1px solid var(--widget-color);\n margin-top: 0;\n padding-top: var(--spacing);\n}\n.lil-gui .lil-gui .lil-gui > .title {\n border: none;\n}\n.lil-gui .lil-gui .lil-gui > .children {\n border: none;\n margin-left: var(--folder-indent);\n border-left: 2px solid var(--widget-color);\n}\n.lil-gui .lil-gui .controller {\n border: none;\n}\n\n.lil-gui input {\n -webkit-tap-highlight-color: transparent;\n border: 0;\n outline: none;\n font-family: var(--font-family);\n font-size: var(--input-font-size);\n border-radius: var(--widget-border-radius);\n height: var(--widget-height);\n background: var(--widget-color);\n color: var(--text-color);\n width: 100%;\n}\n@media (hover: hover) {\n .lil-gui input:hover {\n background: var(--hover-color);\n }\n .lil-gui input:active {\n background: var(--focus-color);\n }\n}\n.lil-gui input:disabled {\n opacity: 1;\n}\n.lil-gui input[type=text],\n.lil-gui input[type=number] {\n padding: var(--widget-padding);\n}\n.lil-gui input[type=text]:focus,\n.lil-gui input[type=number]:focus {\n background: var(--focus-color);\n}\n.lil-gui input::-webkit-outer-spin-button,\n.lil-gui input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n.lil-gui input[type=number] {\n -moz-appearance: textfield;\n}\n.lil-gui input[type=checkbox] {\n appearance: none;\n -webkit-appearance: none;\n height: var(--checkbox-size);\n width: var(--checkbox-size);\n border-radius: var(--widget-border-radius);\n text-align: center;\n cursor: pointer;\n}\n.lil-gui input[type=checkbox]:checked:before {\n font-family: \"lil-gui\";\n content: \"✓\";\n font-size: var(--checkbox-size);\n line-height: var(--checkbox-size);\n}\n@media (hover: hover) {\n .lil-gui input[type=checkbox]:focus {\n box-shadow: inset 0 0 0 1px var(--focus-color);\n }\n}\n.lil-gui button {\n -webkit-tap-highlight-color: transparent;\n outline: none;\n cursor: pointer;\n font-family: var(--font-family);\n font-size: var(--font-size);\n color: var(--text-color);\n width: 100%;\n height: var(--widget-height);\n text-transform: none;\n background: var(--widget-color);\n border-radius: var(--widget-border-radius);\n border: 1px solid var(--widget-color);\n text-align: center;\n line-height: calc(var(--widget-height) - 4px);\n}\n@media (hover: hover) {\n .lil-gui button:hover {\n background: var(--hover-color);\n border-color: var(--hover-color);\n }\n .lil-gui button:focus {\n border-color: var(--focus-color);\n }\n}\n.lil-gui button:active {\n background: var(--focus-color);\n}\n\n@font-face {\n font-family: \"lil-gui\";\n src: url(\"data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAUsAAsAAAAACJwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAAH4AAADAImwmYE9TLzIAAAGIAAAAPwAAAGBKqH5SY21hcAAAAcgAAAD0AAACrukyyJBnbHlmAAACvAAAAF8AAACEIZpWH2hlYWQAAAMcAAAAJwAAADZfcj2zaGhlYQAAA0QAAAAYAAAAJAC5AHhobXR4AAADXAAAABAAAABMAZAAAGxvY2EAAANsAAAAFAAAACgCEgIybWF4cAAAA4AAAAAeAAAAIAEfABJuYW1lAAADoAAAASIAAAIK9SUU/XBvc3QAAATEAAAAZgAAAJCTcMc2eJxVjbEOgjAURU+hFRBK1dGRL+ALnAiToyMLEzFpnPz/eAshwSa97517c/MwwJmeB9kwPl+0cf5+uGPZXsqPu4nvZabcSZldZ6kfyWnomFY/eScKqZNWupKJO6kXN3K9uCVoL7iInPr1X5baXs3tjuMqCtzEuagm/AAlzQgPAAB4nGNgYRBlnMDAysDAYM/gBiT5oLQBAwuDJAMDEwMrMwNWEJDmmsJwgCFeXZghBcjlZMgFCzOiKOIFAB71Bb8AeJy1kjFuwkAQRZ+DwRAwBtNQRUGKQ8OdKCAWUhAgKLhIuAsVSpWz5Bbkj3dEgYiUIszqWdpZe+Z7/wB1oCYmIoboiwiLT2WjKl/jscrHfGg/pKdMkyklC5Zs2LEfHYpjcRoPzme9MWWmk3dWbK9ObkWkikOetJ554fWyoEsmdSlt+uR0pCJR34b6t/TVg1SY3sYvdf8vuiKrpyaDXDISiegp17p7579Gp3p++y7HPAiY9pmTibljrr85qSidtlg4+l25GLCaS8e6rRxNBmsnERunKbaOObRz7N72ju5vdAjYpBXHgJylOAVsMseDAPEP8LYoUHicY2BiAAEfhiAGJgZWBgZ7RnFRdnVJELCQlBSRlATJMoLV2DK4glSYs6ubq5vbKrJLSbGrgEmovDuDJVhe3VzcXFwNLCOILB/C4IuQ1xTn5FPilBTj5FPmBAB4WwoqAHicY2BkYGAA4sk1sR/j+W2+MnAzpDBgAyEMQUCSg4EJxAEAwUgFHgB4nGNgZGBgSGFggJMhDIwMqEAYAByHATJ4nGNgAIIUNEwmAABl3AGReJxjYAACIQYlBiMGJ3wQAEcQBEV4nGNgZGBgEGZgY2BiAAEQyQWEDAz/wXwGAAsPATIAAHicXdBNSsNAHAXwl35iA0UQXYnMShfS9GPZA7T7LgIu03SSpkwzYTIt1BN4Ak/gKTyAeCxfw39jZkjymzcvAwmAW/wgwHUEGDb36+jQQ3GXGot79L24jxCP4gHzF/EIr4jEIe7wxhOC3g2TMYy4Q7+Lu/SHuEd/ivt4wJd4wPxbPEKMX3GI5+DJFGaSn4qNzk8mcbKSR6xdXdhSzaOZJGtdapd4vVPbi6rP+cL7TGXOHtXKll4bY1Xl7EGnPtp7Xy2n00zyKLVHfkHBa4IcJ2oD3cgggWvt/V/FbDrUlEUJhTn/0azVWbNTNr0Ens8de1tceK9xZmfB1CPjOmPH4kitmvOubcNpmVTN3oFJyjzCvnmrwhJTzqzVj9jiSX911FjeAAB4nG3HMRKCMBBA0f0giiKi4DU8k0V2GWbIZDOh4PoWWvq6J5V8If9NVNQcaDhyouXMhY4rPTcG7jwYmXhKq8Wz+p762aNaeYXom2n3m2dLTVgsrCgFJ7OTmIkYbwIbC6vIB7WmFfAAAA==\") format(\"woff\");\n}\n.curve-editor {\n display: flex;\n flex-direction: column;\n gap: 5px;\n background-color: #303030;\n outline: 1px solid #000000;\n padding: 5px;\n width: 100%;\n}\n.curve-editor .button-medium {\n background-color: #545454;\n min-width: var(--widget-height);\n min-height: var(--widget-height);\n height: 100%;\n outline: 1px solid #3c3c3c;\n display: flex;\n justify-content: center;\n align-items: center;\n color: #fff;\n font-size: var(--input-font-size, 11px);\n}\n.curve-editor .button-medium.selected {\n background-color: #4772b3;\n pointer-events: none;\n}\n.curve-editor .button-medium:hover {\n background-color: #656565;\n cursor: default;\n}\n.curve-editor .curve-top {\n display: flex;\n width: 100%;\n}\n.curve-editor .curve-panel {\n width: 100%;\n height: 90px;\n outline: 1px solid #646464;\n}\n.curve-editor .curve-point-panel {\n display: flex;\n align-items: center;\n width: 100%;\n height: var(--widget-height);\n}\n.curve-editor .curve-point-panel input {\n background-color: #545454;\n height: 100%;\n width: 100%;\n color: #fff;\n border: 0;\n outline: 1px solid #3c3c3c;\n text-align: center;\n font-size: var(--input-font-size, 11px);\n}";
25
+ var TextureUtils__namespace = /*#__PURE__*/_interopNamespaceDefault(TextureUtils);
26
+
27
+ var e=[],t=[];function n(n,r){if(n&&"undefined"!=typeof document){var a,s=true===r.prepend?"prepend":"append",d=true===r.singleTag,i="string"==typeof r.container?document.querySelector(r.container):document.getElementsByTagName("head")[0];if(d){var u=e.indexOf(i);-1===u&&(u=e.push(i)-1,t[u]={}),a=t[u]&&t[u][s]?t[u][s]:t[u][s]=c();}else a=c();65279===n.charCodeAt(0)&&(n=n.substring(1)),a.styleSheet?a.styleSheet.cssText+=n:a.appendChild(document.createTextNode(n));}function c(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),r.attributes)for(var t=Object.keys(r.attributes),n=0;n<t.length;n++)e.setAttribute(t[n],r.attributes[t[n]]);var a="prepend"===s?"afterbegin":"beforeend";return i.insertAdjacentElement(a,e),e}}
28
+
29
+ var css = "/* lil-gui CSS - Main entry point */\n\n/* Import all CSS modules */\n/* Base styles and CSS variables for lil-gui */\n/* Font face for icons */\n@font-face {\n\tfont-family: 'lil-gui';\n\tsrc: url('data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAUsAAsAAAAACJwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAAH4AAADAImwmYE9TLzIAAAGIAAAAPwAAAGBKqH5SY21hcAAAAcgAAAD0AAACrukyyJBnbHlmAAACvAAAAF8AAACEIZpWH2hlYWQAAAMcAAAAJwAAADZfcj2zaGhlYQAAA0QAAAAYAAAAJAC5AHhobXR4AAADXAAAABAAAABMAZAAAGxvY2EAAANsAAAAFAAAACgCEgIybWF4cAAAA4AAAAAeAAAAIAEfABJuYW1lAAADoAAAASIAAAIK9SUU/XBvc3QAAATEAAAAZgAAAJCTcMc2eJxVjbEOgjAURU+hFRBK1dGRL+ALnAiToyMLEzFpnPz/eAshwSa97517c/MwwJmeB9kwPl+0cf5+uGPZXsqPu4nvZabcSZldZ6kfyWnomFY/eScKqZNWupKJO6kXN3K9uCVoL7iInPr1X5baXs3tjuMqCtzEuagm/AAlzQgPAAB4nGNgYRBlnMDAysDAYM/gBiT5oLQBAwuDJAMDEwMrMwNWEJDmmsJwgCFeXZghBcjlZMgFCzOiKOIFAB71Bb8AeJy1kjFuwkAQRZ+DwRAwBtNQRUGKQ8OdKCAWUhAgKLhIuAsVSpWz5Bbkj3dEgYiUIszqWdpZe+Z7/wB1oCYmIoboiwiLT2WjKl/jscrHfGg/pKdMkyklC5Zs2LEfHYpjcRoPzme9MWWmk3dWbK9ObkWkikOetJ554fWyoEsmdSlt+uR0pCJR34b6t/TVg1SY3sYvdf8vuiKrpyaDXDISiegp17p7579Gp3p++y7HPAiY9pmTibljrr85qSidtlg4+l25GLCaS8e6rRxNBmsnERunKbaOObRz7N72ju5vdAjYpBXHgJylOAVsMseDAPEP8LYoUHicY2BiAAEfhiAGJgZWBgZ7RnFRdnVJELCQlBSRlATJMoLV2DK4glSYs6ubq5vbKrJLSbGrgEmovDuDJVhe3VzcXFwNLCOILB/C4IuQ1xTn5FPilBTj5FPmBAB4WwoqAHicY2BkYGAA4sk1sR/j+W2+MnAzpDBgAyEMQUCSg4EJxAEAwUgFHgB4nGNgZGBgSGFggJMhDIwMqEAYAByHATJ4nGNgAIIUNEwmAABl3AGReJxjYAACIQYlBiMGJ3wQAEcQBEV4nGNgZGBgEGZgY2BiAAEQyQWEDAz/wXwGAAsPATIAAHicXdBNSsNAHAXwl35iA0UQXYnMShfS9GPZA7T7LgIu03SSpkwzYTIt1BN4Ak/gKTyAeCxfw39jZkjymzcvAwmAW/wgwHUEGDb36+jQQ3GXGot79L24jxCP4gHzF/EIr4jEIe7wxhOC3g2TMYy4Q7+Lu/SHuEd/ivt4wJd4wPxbPEKMX3GI5+DJFGaSn4qNzk8mcbKSR6xdXdhSzaOZJGtdapd4vVPbi6rP+cL7TGXOHtXKll4bY1Xl7EGnPtp7Xy2n00zyKLVHfkHBa4IcJ2oD3cgggWvt/V/FbDrUlEUJhTn/0azVWbNTNr0Ens8de1tceK9xZmfB1CPjOmPH4kitmvOubcNpmVTN3oFJyjzCvnmrwhJTzqzVj9jiSX911FjeAAB4nG3HMRKCMBBA0f0giiKi4DU8k0V2GWbIZDOh4PoWWvq6J5V8If9NVNQcaDhyouXMhY4rPTcG7jwYmXhKq8Wz+p762aNaeYXom2n3m2dLTVgsrCgFJ7OTmIkYbwIbC6vIB7WmFfAAAA==') format('woff');\n}\n/* CSS Variables - Unified Theme */\n:root {\n\t/* Colors */\n\t--bg-primary: #2a2a2a;\n\t--bg-secondary: #1e1e1e;\n\t--bg-tertiary: #323232;\n\t--bg-widget: #3c3c3c;\n\t--bg-hover: #4a4a4a;\n\t--bg-focus: #4d90fe;\n\t--bg-active: #4d90fe;\n\t--bg-selected: #185fbd;\n\n\t--text-primary: #d9d9d9;\n\t--text-muted: #a0a0a0;\n\t--text-number: #d9d9d9;\n\t--text-string: #a2db3c;\n\t--text-warning: #ff8c00;\n\t--text-error: #ff6b6b;\n\t--text-success: #4caf50;\n\n\t/* Typography */\n\t--font-size: 12px;\n\t--font-size-input: 12px;\n\t--font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;\n\t--font-family-mono: Menlo, Monaco, Consolas, 'Droid Sans Mono', monospace;\n\n\t/* Layout */\n\t--padding: 4px;\n\t--spacing: 4px;\n\t--widget-height: 20px;\n\t--title-height: 25px;\n\t--name-width: 40%;\n\t--border-radius: 2px;\n\n\t/* Components */\n\t--slider-knob-width: 2px;\n\t--slider-input-width: 27%;\n\t--color-input-width: 27%;\n\t--slider-input-min-width: 45px;\n\t--color-input-min-width: 65px;\n\t--folder-indent: 7px;\n\t--checkbox-size: 15px;\n\t--scrollbar-width: 5px;\n\n\t/* Effects */\n\t--text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);\n\t--text-shadow-light: 0 1px 1px rgba(0, 0, 0, 0.6);\n}\n/* Touch device overrides */\n@media (pointer: coarse) {\n\t:root {\n\t\t--widget-height: 28px;\n\t\t--padding: 6px;\n\t\t--spacing: 6px;\n\t\t--font-size: 13px;\n\t\t--font-size-input: 16px;\n\t\t--folder-indent: 10px;\n\t\t--scrollbar-width: 7px;\n\t\t--slider-input-min-width: 50px;\n\t\t--color-input-min-width: 65px;\n\t}\n}\n/* Base styles */\n.lil-gui {\n\tfont-family: var(--font-family);\n\tfont-size: var(--font-size);\n\tline-height: 1;\n\tfont-weight: normal;\n\tfont-style: normal;\n\ttext-align: left;\n\tbackground-color: var(--bg-primary);\n\tcolor: var(--text-primary);\n\tuser-select: none;\n\t-webkit-user-select: none;\n\ttouch-action: manipulation;\n\ttext-shadow: var(--text-shadow);\n}\n.lil-gui,\n.lil-gui * {\n\tbox-sizing: border-box;\n\tmargin: 0;\n\tborder-radius: var(--border-radius);\n\tpadding: 1px 0;\n}\n/* Root container */\n.lil-gui.root {\n\twidth: var(--width, 245px);\n\tdisplay: flex;\n\tflex-direction: column;\n}\n.lil-gui.root>.title {\n\tbackground: var(--bg-secondary);\n\tcolor: var(--text-primary);\n\tmargin: 1px 2px;\n}\n.lil-gui.root>.children {\n\toverflow-x: hidden;\n\toverflow-y: auto;\n\tpadding: 0 2px 0;\n\tmargin: 0;\n}\n/* Scrollbar styles */\n.lil-gui.root>.children::-webkit-scrollbar,\n.scene-tree-container::-webkit-scrollbar {\n\twidth: var(--scrollbar-width);\n\theight: var(--scrollbar-width);\n\tbackground: var(--bg-primary);\n}\n.lil-gui.root>.children::-webkit-scrollbar-thumb,\n.scene-tree-container::-webkit-scrollbar-thumb {\n\tborder-radius: var(--scrollbar-width);\n\tbackground: var(--bg-focus);\n}\n.scene-tree-container::-webkit-scrollbar-thumb:hover {\n\tbackground: var(--text-primary);\n}\n/* Auto placement */\n.lil-gui.autoPlace {\n\tmax-height: 100%;\n\tposition: fixed;\n\ttop: 0;\n\tright: 15px;\n\tz-index: 1001;\n}\n/* Title styles */\n.lil-gui .title {\n\theight: var(--title-height);\n\tline-height: calc(var(--title-height) - 4px);\n\tfont-weight: normal;\n\tfont-size: var(--font-size);\n\tpadding: 0 var(--padding);\n\t-webkit-tap-highlight-color: transparent;\n\tcursor: pointer;\n\toutline: none;\n\ttext-decoration-skip: objects;\n\ttext-shadow: var(--text-shadow);\n}\n.lil-gui .title:before {\n\tfont-family: 'lil-gui';\n\tcontent: '▾';\n\tpadding-right: 2px;\n\tdisplay: inline-block;\n}\n/* Title states */\n.lil-gui .title:hover,\n.lil-gui .title:focus,\n.lil-gui .title:active {\n\tbackground: var(--bg-hover);\n\ttext-decoration: none;\n}\n.lil-gui .title:active {\n\topacity: 0.75;\n}\n/* Closed state */\n.lil-gui.closed>.title:before {\n\tcontent: '▸';\n}\n.lil-gui.closed>.children {\n\ttransform: translateY(-7px);\n\topacity: 0;\n}\n.lil-gui.closed:not(.transition)>.children {\n\tdisplay: none;\n}\n/* Transition state */\n.lil-gui.transition>.children {\n\ttransition: height 300ms, opacity 300ms, transform 300ms;\n\ttransition-timing-function: cubic-bezier(0.2, 0.6, 0.35, 1);\n\toverflow: hidden;\n\tpointer-events: none;\n}\n/* Empty children */\n.lil-gui .children:empty:before {\n\tcontent: 'Empty';\n\tpadding: 0 var(--padding);\n\tmargin: var(--spacing) 0;\n\tdisplay: block;\n\theight: var(--widget-height);\n\tfont-style: italic;\n\tline-height: var(--widget-height);\n\topacity: 0.5;\n}\n/* Dragging state */\n.lil-gui-dragging .lil-gui {\n\t--bg-hover: var(--bg-widget);\n}\n.lil-gui-dragging * {\n\tcursor: ew-resize !important;\n}\n.lil-gui-dragging.lil-gui-vertical * {\n\tcursor: ns-resize !important;\n}\n/* Controller styles for lil-gui */\n/* Base controller */\n.lil-gui .controller {\n\tdisplay: flex;\n\talign-items: center;\n\tpadding: 0 var(--padding);\n\tmargin: 0;\n}\n.lil-gui .controller.disabled {\n\topacity: 0.5;\n\tpointer-events: none !important;\n}\n.lil-gui .controller > .name {\n\tmin-width: var(--name-width);\n\tflex-shrink: 0;\n\twhite-space: pre;\n\tpadding-right: var(--spacing);\n\tline-height: var(--widget-height);\n\ttext-shadow: var(--text-shadow-light);\n}\n.lil-gui .controller .widget {\n\tposition: relative;\n\tdisplay: flex;\n\talign-items: center;\n\twidth: 100%;\n\tmin-height: var(--widget-height);\n}\n/* String controller */\n.lil-gui .controller.string input {\n\tcolor: var(--text-string);\n}\n/* Boolean controller */\n.lil-gui .controller.boolean .widget {\n\tcursor: pointer;\n}\n/* Color controller */\n.lil-gui .controller.color .display {\n\twidth: 100%;\n\theight: var(--widget-height);\n\tborder-radius: var(--border-radius);\n\tposition: relative;\n}\n.lil-gui .controller.color .display:hover:before {\n\tcontent: ' ';\n\tdisplay: block;\n\tposition: absolute;\n\tborder-radius: var(--border-radius);\n\tborder: 1px solid #fff9;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\tleft: 0;\n}\n.lil-gui .controller.color input[type='color'] {\n\topacity: 0;\n\twidth: 100%;\n\theight: 100%;\n\tcursor: pointer;\n}\n.lil-gui .controller.color input[type='text'] {\n\tmargin-left: var(--spacing);\n\tfont-family: var(--font-family-mono);\n\tmin-width: var(--color-input-min-width);\n\twidth: var(--color-input-width);\n\tflex-shrink: 0;\n}\n/* Option controller */\n.lil-gui .controller.option select {\n\topacity: 0;\n\tposition: absolute;\n\twidth: 100%;\n\tmax-width: 100%;\n}\n.lil-gui .controller.option .display {\n\tposition: relative;\n\tpointer-events: none;\n\tborder-radius: var(--border-radius);\n\theight: var(--widget-height);\n\tline-height: var(--widget-height);\n\tmax-width: 100%;\n\toverflow: hidden;\n\tword-break: break-all;\n\tpadding-left: 0.55em;\n\tpadding-right: 1.75em;\n\tbackground: var(--bg-widget);\n\ttext-shadow: var(--text-shadow);\n}\n.lil-gui .controller.option .display.focus,\n.lil-gui .controller.option .display.active {\n\tbackground: var(--bg-focus);\n}\n.lil-gui .controller.option .display:after {\n\tfont-family: 'lil-gui';\n\tcontent: '↕';\n\tposition: absolute;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\tpadding-right: 0.375em;\n}\n.lil-gui .controller.option .widget,\n.lil-gui .controller.option select {\n\tcursor: pointer;\n}\n.lil-gui .controller.option .widget:hover .display {\n\tbackground: var(--bg-hover);\n}\n/* Number controller */\n.lil-gui .controller.number input {\n\tcolor: var(--text-number);\n}\n.lil-gui .controller.number.hasSlider input {\n\tmargin-left: var(--spacing);\n\twidth: var(--slider-input-width);\n\tmin-width: var(--slider-input-min-width);\n\tflex-shrink: 0;\n}\n.lil-gui .controller.number .slider {\n\twidth: 100%;\n\theight: var(--widget-height);\n\tbackground-color: var(--bg-widget);\n\tborder-radius: var(--border-radius);\n\tpadding-right: var(--slider-knob-width);\n\toverflow: hidden;\n\tcursor: ew-resize;\n\ttouch-action: pan-y;\n}\n.lil-gui .controller.number .slider:hover {\n\tbackground-color: var(--bg-hover);\n}\n.lil-gui .controller.number .slider.active {\n\tbackground-color: var(--bg-active);\n}\n.lil-gui .controller.number .slider.active .fill {\n\topacity: 0.95;\n}\n.lil-gui .controller.number .fill {\n\theight: 100%;\n\tborder-right: var(--slider-knob-width) solid var(--text-number);\n\tbox-sizing: content-box;\n}\n/* Texture controller */\n.lil-gui .controller.texture canvas {\n\twidth: 100%;\n\tborder-radius: var(--border-radius);\n}\n.lil-gui .controller.texture .group {\n\tdisplay: flex;\n\tposition: relative;\n\twidth: 100%;\n}\n.lil-gui .controller.texture .info {\n\tposition: absolute;\n\tdisplay: flex;\n\tgap: 11px;\n}\n.lil-gui .controller.texture .label {\n\tposition: absolute;\n\tbackground-color: #000000ac;\n\tdisplay: flex;\n\tpadding: 2px;\n\tborder-radius: var(--border-radius);\n}\n.lil-gui .controller.texture .block {\n\tposition: absolute;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tmargin-top: 2px;\n\twidth: var(--font-size);\n\theight: var(--font-size);\n\tborder-radius: var(--font-size);\n\tbackground-color: white;\n\tcursor: pointer;\n}\n.lil-gui .controller.texture .block.select {\n\tbackground-color: var(--text-string);\n}\n/* Image controller */\n.lil-gui .controller.image img,\n.lil-gui .controller.image canvas {\n\twidth: 100%;\n}\n/* Vector controller */\n.lil-gui .controller.vector input {\n\tcolor: var(--text-number);\n}\n.lil-gui .controller.vector .fill {\n\theight: 100%;\n\tmargin-left: var(--spacing);\n\tbox-sizing: content-box;\n}\n/* Input and form control styles for lil-gui */\n/* Base input styles */\n.lil-gui input {\n\t-webkit-tap-highlight-color: transparent;\n\tborder: 0;\n\toutline: none;\n\tfont-family: var(--font-family);\n\tfont-size: var(--font-size-input);\n\tborder-radius: var(--border-radius);\n\theight: var(--widget-height);\n\tbackground: var(--bg-widget);\n\tcolor: var(--text-primary);\n\twidth: 100%;\n\ttext-shadow: var(--text-shadow-light);\n}\n.lil-gui input:hover {\n\tbackground: var(--bg-hover);\n}\n.lil-gui input:focus {\n\tbackground: var(--bg-focus);\n}\n.lil-gui input:disabled {\n\topacity: 1;\n}\n/* Text and number inputs */\n.lil-gui input[type='text'],\n.lil-gui input[type='number'] {\n\tpadding: 0 0 0 3px;\n}\n/* Hide number spinners */\n.lil-gui input::-webkit-outer-spin-button,\n.lil-gui input::-webkit-inner-spin-button {\n\t-webkit-appearance: none;\n\tmargin: 0;\n}\n.lil-gui input[type='number'] {\n\t-moz-appearance: textfield;\n}\n/* Checkbox */\n.lil-gui input[type='checkbox'] {\n\tappearance: none;\n\t-webkit-appearance: none;\n\theight: var(--checkbox-size);\n\twidth: var(--checkbox-size);\n\tborder-radius: var(--border-radius);\n\ttext-align: center;\n\tcursor: pointer;\n}\n.lil-gui input[type='checkbox']:checked:before {\n\tfont-family: 'lil-gui';\n\tcontent: '✓';\n\tfont-size: var(--checkbox-size);\n\tline-height: var(--checkbox-size);\n}\n.lil-gui input[type='checkbox']:focus {\n\tbox-shadow: inset 0 0 0 1px var(--bg-active);\n}\n/* Button */\n.lil-gui button {\n\t-webkit-tap-highlight-color: transparent;\n\toutline: none;\n\tcursor: pointer;\n\tfont-family: var(--font-family);\n\tfont-size: var(--font-size);\n\tcolor: var(--text-primary);\n\twidth: 100%;\n\theight: var(--widget-height);\n\ttext-transform: none;\n\tbackground: var(--bg-widget);\n\tborder-radius: var(--border-radius);\n\tborder: 1px solid var(--bg-widget);\n\ttext-align: center;\n\tline-height: calc(var(--widget-height) - 4px);\n\ttext-shadow: var(--text-shadow);\n}\n.lil-gui button:hover {\n\tbackground: var(--bg-hover);\n\tborder-color: var(--bg-hover);\n}\n.lil-gui button:focus {\n\tborder-color: var(--bg-active);\n}\n.lil-gui button:active {\n\tbackground: var(--bg-active);\n}\n/* Curve editor styles for lil-gui */\n.curve-editor {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 5px;\n\tbackground-color: var(--bg-tertiary);\n\toutline: 1px solid #000000;\n\tpadding: 5px;\n\twidth: 100%;\n}\n.curve-editor .button-medium {\n\tbackground-color: #545454;\n\tmin-width: var(--widget-height);\n\tmin-height: var(--widget-height);\n\theight: 100%;\n\toutline: 1px solid var(--bg-widget);\n\tdisplay: flex;\n\tjustify-content: center;\n\talign-items: center;\n\tcolor: #fff;\n\tfont-size: var(--font-size-input);\n}\n.curve-editor .button-medium.selected {\n\tbackground-color: var(--bg-active);\n\tpointer-events: none;\n}\n.curve-editor .button-medium:hover {\n\tbackground-color: #656565;\n\tcursor: default;\n}\n.curve-editor .curve-top {\n\tdisplay: flex;\n\twidth: 100%;\n}\n.curve-editor .curve-panel {\n\twidth: 100%;\n\theight: 90px;\n\toutline: 1px solid #646464;\n}\n.curve-editor .curve-point-panel {\n\tdisplay: flex;\n\talign-items: center;\n\twidth: 100%;\n\theight: var(--widget-height);\n}\n.curve-editor .curve-point-panel input {\n\tbackground-color: #545454;\n\theight: 100%;\n\twidth: 100%;\n\tcolor: #fff;\n\tborder: 0;\n\toutline: 1px solid var(--bg-widget);\n\ttext-align: center;\n\tfont-size: var(--font-size-input);\n}\n/* Scene Tree Controller Styles */\n/* Base styles for scene tree */\n.scene-tree-container,\n.scene-tree-controller {\n\twidth: 100%;\n}\n.scene-tree-container {\n\theight: 100%;\n\toverflow-y: auto;\n\toverflow-x: hidden;\n\tposition: relative;\n\tpadding: 0;\n}\n.scene-tree-controller {\n\tfont-family: var(--font-family);\n\tfont-size: var(--font-size);\n\tmax-height: 300px;\n\toverflow-y: auto;\n\tborder: none;\n\tpadding: 0 !important;\n}\n/* Scene tree node */\n.scene-tree-controller .scene-tree-node {\n\ttransition: background-color 200ms ease;\n\tborder-radius: 0;\n\tpadding: 2px var(--padding);\n\tmargin: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tcursor: pointer;\n\tuser-select: none;\n\tmin-height: 24px;\n\twidth: 100%;\n\tbox-sizing: border-box;\n\tposition: relative;\n\theight: var(--title-height);\n\tline-height: calc(var(--title-height) - 4px);\n}\n/* Alternating background colors */\n.scene-tree-controller .scene-tree-node.even-row {\n\tbackground-color: var(--bg-primary);\n}\n.scene-tree-controller .scene-tree-node.odd-row {\n\tbackground-color: var(--bg-tertiary);\n}\n.scene-tree-controller .scene-tree-node:hover {\n\tbackground-color: var(--bg-hover);\n}\n.scene-tree-controller .scene-tree-node.selected {\n\tbackground-color: var(--bg-active);\n\tcolor: #ffffff;\n}\n/* Expand button */\n.scene-tree-controller .scene-tree-node .expand-btn {\n\tcursor: pointer;\n\tuser-select: none;\n\ttransition: all 300ms;\n\tdisplay: inline-block;\n\theight: 16px;\n\tflex-shrink: 0;\n\tfont-family: 'lil-gui';\n\tfont-size: var(--font-size);\n\tline-height: 1;\n\tcolor: var(--text-primary);\n\ttext-align: center;\n\topacity: 0.8;\n}\n.scene-tree-controller .scene-tree-node .expand-btn:hover {\n\topacity: 1;\n}\n/* Visibility button */\n.scene-tree-controller .scene-tree-node .visibility-btn {\n\tcursor: pointer;\n\tuser-select: none;\n\ttransition: all 300ms;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n\tborder-radius: var(--border-radius);\n\tmargin-left: auto;\n\tflex-shrink: 0;\n\topacity: 0.8;\n}\n.scene-tree-controller .scene-tree-node .visibility-btn:hover {\n\tbackground-color: var(--bg-secondary);\n\topacity: 0.8;\n}\n.scene-tree-controller .scene-tree-node .visibility-btn svg {\n\twidth: 16px;\n\theight: 16px;\n\tfill: var(--text-primary);\n}\n.scene-tree-controller .scene-tree-node .visibility-btn.hidden svg {\n\topacity: 0.6;\n}\n.scene-tree-controller .scene-tree-node .visibility-btn:hover {\n\topacity: 1;\n}\n/* Node info */\n.scene-tree-controller .scene-tree-node .node-info {\n\tflex: 1;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--text-primary);\n\tfont-size: var(--font-size);\n\tmargin-right: var(--spacing);\n\tmin-width: 0;\n\tpadding-left: 0;\n\ttext-shadow: var(--text-shadow);\n}\n/* Context Menu Styles - Blender-inspired */\n.scene-tree-context-menu {\n\tposition: fixed;\n\tbackground: #202020;\n\tborder-radius: 2px;\n\tbox-shadow: 0 4px 20px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);\n\tz-index: 10000;\n\tmin-width: 100px;\n\tpadding: 4px;\n\tfont-family: var(--font-family);\n\tfont-size: var(--font-size);\n\tcolor: #e0e0e0;\n}\n.scene-tree-context-menu .context-menu-item {\n\theight: 20px;\n\tline-height: 20px;\n\tpadding: 0 16px;\n\tcursor: pointer;\n\tdisplay: flex;\n\talign-items: center;\n\tcolor: #e0e0e0;\n\ttransition: all 0.1s ease;\n\tuser-select: none;\n\t-webkit-tap-highlight-color: transparent;\n\toutline: none;\n\ttext-decoration-skip: objects;\n\tfont-weight: 400;\n\tborder-radius: 2px;\n}\n.scene-tree-context-menu .context-menu-item:hover {\n\tbackground: #3a3a3a;\n\tcolor: #ffffff;\n}\n.scene-tree-context-menu .context-menu-item:active {\n\tbackground: #4a4a4a;\n\tcolor: #ffffff;\n}\n/* Context menu separator */\n.scene-tree-context-menu .context-menu-separator {\n\theight: 1px;\n\tbackground-color: #404040;\n\tmargin: 4px 0;\n}\n/* Disabled state for paste when clipboard is empty */\n.scene-tree-context-menu .context-menu-item.disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n\tcolor: #808080;\n}\n.scene-tree-context-menu .context-menu-item.disabled:hover,\n.scene-tree-context-menu .context-menu-item.disabled:focus,\n.scene-tree-context-menu .context-menu-item.disabled:active {\n\tbackground: transparent;\n\tcolor: #808080;\n}\n\n\n";
9
30
  n(css,{});
10
31
 
11
32
  class Controller {
@@ -319,13 +340,7 @@ class OptionController extends Controller {
319
340
  this.$select.setAttribute('aria-labelledby', this.$name.id);
320
341
  this.$display = document.createElement('div');
321
342
  this.$display.classList.add('display');
322
- this._values = Array.isArray(options) ? options : Object.values(options);
323
- this._names = Array.isArray(options) ? options : Object.keys(options);
324
- this._names.forEach((name)=>{
325
- const $option = document.createElement('option');
326
- $option.innerHTML = name;
327
- this.$select.appendChild($option);
328
- });
343
+ this.options(options);
329
344
  this.$select.addEventListener('change', ()=>{
330
345
  this.setValue(this._values[this.$select.selectedIndex]);
331
346
  this._callOnFinishChange();
@@ -883,10 +898,7 @@ class ColorController extends Controller {
883
898
  return this;
884
899
  }
885
900
  constructor(parent, object, property, rgbScale){
886
- super(parent, object, property, 'color');
887
- this._textFocused = false;
888
- this._initialValueHexString = "";
889
- this._rgbScale = 1;
901
+ super(parent, object, property, 'color'), this._textFocused = false, this._initialValueHexString = "", this._rgbScale = 1;
890
902
  this.$input = document.createElement('input');
891
903
  this.$input.setAttribute('type', 'color');
892
904
  this.$input.setAttribute('tabindex', "-1");
@@ -1042,13 +1054,7 @@ class UINumber extends UIElement {
1042
1054
  return this;
1043
1055
  }
1044
1056
  constructor(value, min, max, step){
1045
- super(document.createElement('input'));
1046
- this.value = 0;
1047
- this.min = -Infinity;
1048
- this.max = Infinity;
1049
- this.step = 1;
1050
- this.nudge = 1;
1051
- this.unit = "";
1057
+ super(document.createElement('input')), this.value = 0, this.min = -Infinity, this.max = Infinity, this.step = 1, this.nudge = 1, this.unit = "";
1052
1058
  this.dom.style.cursor = 'ns-resize';
1053
1059
  this.dom.value = '0.00';
1054
1060
  this.min = min != null ? min : this.min;
@@ -1706,7 +1712,7 @@ class TextureController extends Controller {
1706
1712
  canvas.title = texture.sourceFile || "";
1707
1713
  canvas.height = canvas.width / image.width * image.height;
1708
1714
  if (this.getImage) {
1709
- const w = 256, h = 256 / image.width * image.height;
1715
+ const w = 256, h = Math.floor(256 / image.width * image.height);
1710
1716
  context.drawImage(this.getImage(texture, w, h), 0, 0, w * 1.5, h * 1.5, 0, 0, canvas.width, canvas.height); //why 1.5 ?
1711
1717
  }
1712
1718
  } else {
@@ -1718,8 +1724,7 @@ class TextureController extends Controller {
1718
1724
  return this;
1719
1725
  }
1720
1726
  constructor(parent, object, property){
1721
- super(parent, object, property, "texture");
1722
- this._autoRefresh = false;
1727
+ super(parent, object, property, "texture"), this._autoRefresh = false;
1723
1728
  const group = this.$widget.appendChild(document.createElement("div"));
1724
1729
  group.classList.add("group");
1725
1730
  this.$canvas = group.appendChild(document.createElement("canvas"));
@@ -1738,6 +1743,486 @@ class TextureController extends Controller {
1738
1743
  }
1739
1744
  }
1740
1745
 
1746
+ class SceneTreeController extends Controller {
1747
+ _setupDOM() {
1748
+ // Hide the name element since we don't need it for scene tree
1749
+ this.$name.style.display = 'none';
1750
+ this.$treeContainer = document.createElement('div');
1751
+ this.$treeContainer.classList.add('scene-tree-container');
1752
+ this.$widget.appendChild(this.$treeContainer);
1753
+ }
1754
+ _createContextMenu() {
1755
+ this._contextMenu = document.createElement('div');
1756
+ this._contextMenu.classList.add('scene-tree-context-menu');
1757
+ this._contextMenu.style.display = 'none';
1758
+ const menuItems = [
1759
+ {
1760
+ label: 'Export',
1761
+ action: 'export'
1762
+ },
1763
+ {
1764
+ label: 'Copy',
1765
+ action: 'copy'
1766
+ },
1767
+ {
1768
+ label: 'Paste',
1769
+ action: 'paste'
1770
+ }
1771
+ ];
1772
+ menuItems.forEach((item)=>{
1773
+ const menuItem = document.createElement('div');
1774
+ menuItem.classList.add('context-menu-item');
1775
+ menuItem.dataset.action = item.action;
1776
+ menuItem.textContent = item.label;
1777
+ menuItem.addEventListener('click', ()=>this._handleContextMenuAction(item.action));
1778
+ this._contextMenu.appendChild(menuItem);
1779
+ });
1780
+ document.body.appendChild(this._contextMenu);
1781
+ }
1782
+ _setupGlobalEventListeners() {
1783
+ // Hide context menu when clicking outside
1784
+ document.addEventListener('click', (e)=>{
1785
+ if (this._contextMenu && !this._contextMenu.contains(e.target)) {
1786
+ this._hideContextMenu();
1787
+ }
1788
+ });
1789
+ // Hide context menu on escape key
1790
+ document.addEventListener('keydown', (e)=>{
1791
+ if (e.key === 'Escape') {
1792
+ this._hideContextMenu();
1793
+ }
1794
+ });
1795
+ }
1796
+ _showContextMenu(x, y, target) {
1797
+ if (!this._contextMenu) return;
1798
+ this._contextMenuTarget = target;
1799
+ this._contextMenu.style.display = 'block';
1800
+ // Update paste menu item state based on clipboard
1801
+ this._updateContextMenuState();
1802
+ // Position the menu
1803
+ const rect = this._contextMenu.getBoundingClientRect();
1804
+ const viewportWidth = window.innerWidth;
1805
+ const viewportHeight = window.innerHeight;
1806
+ // Adjust position if menu would go off-screen
1807
+ let adjustedX = x;
1808
+ let adjustedY = y;
1809
+ if (x + rect.width > viewportWidth) {
1810
+ adjustedX = x - rect.width;
1811
+ }
1812
+ if (y + rect.height > viewportHeight) {
1813
+ adjustedY = y - rect.height;
1814
+ }
1815
+ this._contextMenu.style.left = `${adjustedX}px`;
1816
+ this._contextMenu.style.top = `${adjustedY}px`;
1817
+ }
1818
+ _updateContextMenuState() {
1819
+ if (!this._contextMenu) return;
1820
+ const pasteItem = this._contextMenu.querySelector('[data-action="paste"]');
1821
+ if (pasteItem) {
1822
+ if (this._clipboardData) {
1823
+ pasteItem.classList.remove('disabled');
1824
+ pasteItem.style.cursor = 'pointer';
1825
+ } else {
1826
+ pasteItem.classList.add('disabled');
1827
+ pasteItem.style.cursor = 'not-allowed';
1828
+ }
1829
+ }
1830
+ }
1831
+ _hideContextMenu() {
1832
+ if (this._contextMenu) {
1833
+ this._contextMenu.style.display = 'none';
1834
+ }
1835
+ this._contextMenuTarget = null;
1836
+ }
1837
+ _handleContextMenuAction(action) {
1838
+ if (!this._contextMenuTarget) return;
1839
+ switch(action){
1840
+ case 'export':
1841
+ this._exportObject(this._contextMenuTarget);
1842
+ break;
1843
+ case 'copy':
1844
+ this._copyObject(this._contextMenuTarget);
1845
+ break;
1846
+ case 'paste':
1847
+ if (this._clipboardData) {
1848
+ this._pasteObject(this._contextMenuTarget);
1849
+ }
1850
+ break;
1851
+ }
1852
+ this._hideContextMenu();
1853
+ }
1854
+ _exportObject(node) {
1855
+ try {
1856
+ new Addons.GLTFExporter().setTextureUtils(TextureUtils__namespace).parse(node.object, (result)=>{
1857
+ if (result instanceof ArrayBuffer) {
1858
+ const blob = new Blob([
1859
+ result
1860
+ ], {
1861
+ type: 'application/octet-stream'
1862
+ });
1863
+ const url = URL.createObjectURL(blob);
1864
+ const link = document.createElement('a');
1865
+ link.href = url;
1866
+ link.download = `${node.name || node.type}.glb`;
1867
+ link.click();
1868
+ }
1869
+ }, (err)=>{
1870
+ console.log('An error happened during parsing', err);
1871
+ }, {
1872
+ trs: false,
1873
+ binary: true,
1874
+ maxTextureSize: 4096
1875
+ });
1876
+ console.log(`Exported object: ${node.name || node.type}`);
1877
+ } catch (error) {
1878
+ console.error('Failed to export object:', error);
1879
+ }
1880
+ }
1881
+ _copyObject(node) {
1882
+ try {
1883
+ const copyData = this._serializeObject(node.object);
1884
+ this._clipboardData = copyData;
1885
+ // Also copy to system clipboard if possible
1886
+ if (navigator.clipboard && navigator.clipboard.writeText) {
1887
+ navigator.clipboard.writeText(JSON.stringify(copyData, null, 2));
1888
+ }
1889
+ console.log(`Copied object: ${node.name || node.type}`);
1890
+ } catch (error) {
1891
+ console.error('Failed to copy object:', error);
1892
+ }
1893
+ }
1894
+ _pasteObject(targetNode) {
1895
+ if (!this._clipboardData) {
1896
+ console.warn('No object data in clipboard');
1897
+ return;
1898
+ }
1899
+ try {
1900
+ // Create a new object based on clipboard data
1901
+ const newObject = this._deserializeObject(this._clipboardData);
1902
+ if (newObject) {
1903
+ // Add to the target node's parent
1904
+ const parent = this._findParentNode(targetNode);
1905
+ if (parent) {
1906
+ parent.object.add(newObject);
1907
+ this.refresh();
1908
+ console.log(`Pasted object to: ${parent.name || parent.type}`);
1909
+ }
1910
+ }
1911
+ } catch (error) {
1912
+ console.error('Failed to paste object:', error);
1913
+ }
1914
+ }
1915
+ _serializeObject(obj) {
1916
+ const serialized = {
1917
+ type: obj.type,
1918
+ name: obj.name,
1919
+ uuid: obj.uuid,
1920
+ visible: obj.visible,
1921
+ position: obj.position.toArray(),
1922
+ rotation: obj.rotation.toArray(),
1923
+ scale: obj.scale.toArray(),
1924
+ userData: obj.userData
1925
+ };
1926
+ // Add children if any
1927
+ if (obj.children.length > 0) {
1928
+ serialized.children = obj.children.map((child)=>this._serializeObject(child));
1929
+ }
1930
+ return serialized;
1931
+ }
1932
+ _deserializeObject(data) {
1933
+ try {
1934
+ // This is a simplified deserialization
1935
+ // In a real implementation, you'd want to handle different object types properly
1936
+ const obj = new three.Object3D();
1937
+ obj.name = data.name || data.type;
1938
+ obj.visible = data.visible !== undefined ? data.visible : true;
1939
+ if (data.position) {
1940
+ obj.position.set(data.position[0], data.position[1], data.position[2]);
1941
+ }
1942
+ if (data.rotation) {
1943
+ obj.rotation.set(data.rotation[0], data.rotation[1], data.rotation[2]);
1944
+ }
1945
+ if (data.scale) {
1946
+ obj.scale.set(data.scale[0], data.scale[1], data.scale[2]);
1947
+ }
1948
+ if (data.userData) {
1949
+ obj.userData = {
1950
+ ...data.userData
1951
+ };
1952
+ }
1953
+ return obj;
1954
+ } catch (error) {
1955
+ console.error('Failed to deserialize object:', error);
1956
+ return null;
1957
+ }
1958
+ }
1959
+ _findParentNode(node) {
1960
+ const findParent = (current, target)=>{
1961
+ if (current.children.includes(target)) {
1962
+ return current;
1963
+ }
1964
+ for (const child of current.children){
1965
+ const result = findParent(child, target);
1966
+ if (result) return result;
1967
+ }
1968
+ return null;
1969
+ };
1970
+ return findParent(this._rootNode, node);
1971
+ }
1972
+ _buildSceneTree(scene) {
1973
+ const buildNode = (obj)=>{
1974
+ const children = [];
1975
+ for(let i = 0; i < obj.children.length; i++){
1976
+ children.push(buildNode(obj.children[i]));
1977
+ }
1978
+ return {
1979
+ object: obj,
1980
+ name: obj.name || obj.type,
1981
+ type: obj.type,
1982
+ visible: obj.visible,
1983
+ children: children,
1984
+ expanded: false
1985
+ };
1986
+ };
1987
+ return buildNode(scene);
1988
+ }
1989
+ _renderTree() {
1990
+ this.$treeContainer.innerHTML = '';
1991
+ this._visibleNodeCount = 0; // Reset counter for each render
1992
+ this._renderNode(this._rootNode, 0);
1993
+ }
1994
+ _renderNode(node, depth) {
1995
+ const nodeElement = document.createElement('div');
1996
+ nodeElement.classList.add('scene-tree-node');
1997
+ // Remove marginLeft from the node itself to keep background full width
1998
+ // Add alternating background colors using theme colors
1999
+ // Use a simple counter that increments for each visible node
2000
+ const isEvenRow = this._visibleNodeCount % 2 === 0;
2001
+ nodeElement.classList.add(isEvenRow ? 'even-row' : 'odd-row');
2002
+ this._visibleNodeCount++;
2003
+ // Create a content wrapper for indentation
2004
+ const contentWrapper = document.createElement('div');
2005
+ contentWrapper.style.marginLeft = `${depth * 7}px`;
2006
+ contentWrapper.style.display = 'flex';
2007
+ contentWrapper.style.alignItems = 'center';
2008
+ contentWrapper.style.width = '100%';
2009
+ // Expand/collapse button
2010
+ if (node.children.length > 0) {
2011
+ const expandBtn = document.createElement('span');
2012
+ expandBtn.classList.add('expand-btn');
2013
+ expandBtn.classList.add(node.expanded ? 'expanded' : 'collapsed');
2014
+ expandBtn.textContent = node.expanded ? '▾' : '▸';
2015
+ expandBtn.addEventListener('click', (e)=>{
2016
+ e.stopPropagation();
2017
+ node.expanded = !node.expanded;
2018
+ this._renderTree();
2019
+ });
2020
+ contentWrapper.appendChild(expandBtn);
2021
+ }
2022
+ // Node name and type
2023
+ const nodeInfo = document.createElement('span');
2024
+ nodeInfo.textContent = `${node.name} (${node.type})`;
2025
+ nodeInfo.classList.add('node-info');
2026
+ contentWrapper.appendChild(nodeInfo);
2027
+ // Visibility toggle (moved after node name)
2028
+ const visibilityBtn = document.createElement('span');
2029
+ visibilityBtn.classList.add('visibility-btn');
2030
+ visibilityBtn.classList.add(node.visible ? 'visible' : 'hidden');
2031
+ visibilityBtn.innerHTML = node.visible ? '<svg viewBox="0 0 24 24" width="16" height="16"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></svg>' : '<svg viewBox="0 0 24 24" width="16" height="16"><path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"/></svg>';
2032
+ visibilityBtn.addEventListener('click', (e)=>{
2033
+ e.stopPropagation();
2034
+ node.object.visible = !node.object.visible;
2035
+ node.visible = node.object.visible;
2036
+ this._renderTree();
2037
+ });
2038
+ contentWrapper.appendChild(visibilityBtn);
2039
+ // Add content wrapper to node
2040
+ nodeElement.appendChild(contentWrapper);
2041
+ // Selection indicator
2042
+ if (this._selectedObject === node.object) {
2043
+ nodeElement.classList.add('selected');
2044
+ }
2045
+ // Click to select
2046
+ nodeElement.addEventListener('click', ()=>{
2047
+ this._selectObject(node.object);
2048
+ });
2049
+ // Right-click for context menu
2050
+ nodeElement.addEventListener('contextmenu', (e)=>{
2051
+ e.preventDefault();
2052
+ e.stopPropagation();
2053
+ this._showContextMenu(e.clientX, e.clientY, node);
2054
+ });
2055
+ this.$treeContainer.appendChild(nodeElement);
2056
+ // Render children if expanded
2057
+ if (node.expanded) {
2058
+ node.children.forEach((child)=>{
2059
+ this._renderNode(child, depth + 1);
2060
+ });
2061
+ }
2062
+ }
2063
+ _selectObject(object) {
2064
+ this._selectedObject = object;
2065
+ this._renderTree();
2066
+ if (this._onObjectSelect) {
2067
+ this._onObjectSelect(object);
2068
+ }
2069
+ }
2070
+ onObjectSelect(callback) {
2071
+ this._onObjectSelect = callback;
2072
+ return this;
2073
+ }
2074
+ refresh() {
2075
+ this._rootNode = this._buildSceneTree(this._scene);
2076
+ this._renderTree();
2077
+ }
2078
+ getSelectedObject() {
2079
+ return this._selectedObject;
2080
+ }
2081
+ expandAll() {
2082
+ const expandNode = (node)=>{
2083
+ node.expanded = true;
2084
+ node.children.forEach(expandNode);
2085
+ };
2086
+ expandNode(this._rootNode);
2087
+ this._renderTree();
2088
+ }
2089
+ collapseAll() {
2090
+ const collapseNode = (node)=>{
2091
+ node.expanded = false;
2092
+ node.children.forEach(collapseNode);
2093
+ };
2094
+ collapseNode(this._rootNode);
2095
+ this._renderTree();
2096
+ }
2097
+ update() {
2098
+ // Always update visibility states (lightweight operation)
2099
+ this._updateVisibilityStates(this._rootNode);
2100
+ // Only check for structural changes periodically to avoid performance issues
2101
+ if (this._autoUpdate && this._shouldCheckForChanges()) {
2102
+ this._checkForStructuralChanges();
2103
+ }
2104
+ }
2105
+ _shouldCheckForChanges() {
2106
+ const now = performance.now();
2107
+ if (now - this._lastUpdateTime > this._updateInterval) {
2108
+ this._lastUpdateTime = now;
2109
+ return true;
2110
+ }
2111
+ return false;
2112
+ }
2113
+ setAutoUpdate(enabled) {
2114
+ this._autoUpdate = enabled;
2115
+ }
2116
+ setUpdateInterval(intervalMs) {
2117
+ this._updateInterval = intervalMs;
2118
+ }
2119
+ getUpdateInterval() {
2120
+ return this._updateInterval;
2121
+ }
2122
+ getAutoUpdate() {
2123
+ return this._autoUpdate;
2124
+ }
2125
+ forceUpdate() {
2126
+ this._rootNode = this._buildSceneTree(this._scene);
2127
+ this._renderTree();
2128
+ }
2129
+ _checkForStructuralChanges() {
2130
+ // Use lightweight change detection instead of rebuilding the entire tree
2131
+ if (this._hasSceneStructureChanged()) {
2132
+ this._rebuildSceneTree();
2133
+ }
2134
+ }
2135
+ _hasSceneStructureChanged() {
2136
+ // Quick check for common changes without rebuilding the tree
2137
+ return this._checkObjectCount() || this._checkObjectReferences();
2138
+ }
2139
+ _checkObjectCount() {
2140
+ // Check if the total number of objects has changed
2141
+ const currentCount = this._countObjects(this._scene);
2142
+ if (currentCount !== this._cachedObjectCount) {
2143
+ this._cachedObjectCount = currentCount;
2144
+ return true;
2145
+ }
2146
+ return false;
2147
+ }
2148
+ _checkObjectReferences() {
2149
+ // Check if any object references have changed (objects added/removed)
2150
+ return this._scene.children.length !== this._rootNode.children.length || this._hasChildrenChanged(this._scene, this._rootNode);
2151
+ }
2152
+ _hasChildrenChanged(sceneObj, treeNode) {
2153
+ if (sceneObj.children.length !== treeNode.children.length) return true;
2154
+ for(let i = 0; i < sceneObj.children.length; i++){
2155
+ const sceneChild = sceneObj.children[i];
2156
+ const treeChild = treeNode.children[i];
2157
+ if (sceneChild !== treeChild.object) return true;
2158
+ if (this._hasChildrenChanged(sceneChild, treeChild)) return true;
2159
+ }
2160
+ return false;
2161
+ }
2162
+ _countObjects(obj) {
2163
+ let count = 1;
2164
+ for(let i = 0; i < obj.children.length; i++){
2165
+ count += this._countObjects(obj.children[i]);
2166
+ }
2167
+ return count;
2168
+ }
2169
+ _rebuildSceneTree() {
2170
+ // Only rebuild when necessary
2171
+ const currentStructure = this._buildSceneTree(this._scene);
2172
+ this._preserveExpandedStates(this._rootNode, currentStructure);
2173
+ this._rootNode = currentStructure;
2174
+ this._cachedObjectCount = this._countObjects(this._scene);
2175
+ this._renderTree();
2176
+ }
2177
+ _hasStructureChanged(oldNode, newNode) {
2178
+ if (oldNode.children.length !== newNode.children.length) return true;
2179
+ if (oldNode.object !== newNode.object) return true;
2180
+ for(let i = 0; i < oldNode.children.length; i++){
2181
+ if (this._hasStructureChanged(oldNode.children[i], newNode.children[i])) {
2182
+ return true;
2183
+ }
2184
+ }
2185
+ return false;
2186
+ }
2187
+ _preserveExpandedStates(oldNode, newNode) {
2188
+ // Try to preserve expanded states by matching object references
2189
+ if (oldNode.object === newNode.object) {
2190
+ newNode.expanded = oldNode.expanded;
2191
+ }
2192
+ for(let i = 0; i < Math.min(oldNode.children.length, newNode.children.length); i++){
2193
+ this._preserveExpandedStates(oldNode.children[i], newNode.children[i]);
2194
+ }
2195
+ }
2196
+ _updateVisibilityStates(node) {
2197
+ node.visible = node.object.visible;
2198
+ node.children.forEach((child)=>this._updateVisibilityStates(child));
2199
+ }
2200
+ destroy() {
2201
+ super.destroy();
2202
+ this._onObjectSelect = null;
2203
+ // Clean up context menu
2204
+ if (this._contextMenu && this._contextMenu.parentNode) {
2205
+ this._contextMenu.parentNode.removeChild(this._contextMenu);
2206
+ }
2207
+ this._contextMenu = null;
2208
+ this._contextMenuTarget = null;
2209
+ this._clipboardData = null;
2210
+ }
2211
+ constructor(parent, scene){
2212
+ super(parent, scene, 'sceneTree', 'scene-tree-controller', 'div'), this._selectedObject = null, this._onObjectSelect = null, this._autoUpdate = true, this._cachedObjectCount = 0, this._lastUpdateTime = 0, this._updateInterval = 1000 // Only check for changes every 1 second
2213
+ , this._visibleNodeCount = 0 // Counter for alternating background colors
2214
+ , // Context menu properties
2215
+ this._contextMenu = null, this._contextMenuTarget = null, this._clipboardData = null;
2216
+ this._scene = scene;
2217
+ this._rootNode = this._buildSceneTree(scene);
2218
+ this._cachedObjectCount = this._countObjects(scene);
2219
+ this._setupDOM();
2220
+ this._createContextMenu();
2221
+ this._renderTree();
2222
+ this._setupGlobalEventListeners();
2223
+ }
2224
+ }
2225
+
1741
2226
  class GUI {
1742
2227
  /**
1743
2228
  * Adds a controller to the GUI, inferring controller type using the `typeof` operator.
@@ -1812,6 +2297,13 @@ class GUI {
1812
2297
  addCurve(object, property) {
1813
2298
  return new CurveController(this, object, property);
1814
2299
  }
2300
+ /**
2301
+ * Adds a scene tree controller to display Three.js scene hierarchy.
2302
+ * @param {Scene} scene The Three.js scene to display
2303
+ * @returns {SceneTreeController}
2304
+ */ addSceneTree(scene) {
2305
+ return new SceneTreeController(this, scene);
2306
+ }
1815
2307
  /**
1816
2308
  * Adds a folder to the GUI, which is just another GUI. This method returns
1817
2309
  * the nested GUI so you can add controllers to it.
@@ -1821,8 +2313,6 @@ class GUI {
1821
2313
  * folder.add( position, 'y' );
1822
2314
  * folder.add( position, 'z' );
1823
2315
  *
1824
- * @param {string} title Name to display in the folder's title bar.
1825
- * @param {string} id Id
1826
2316
  * @returns {GUI}
1827
2317
  */ addFolder(title, id = title) {
1828
2318
  const folder = new GUI({
@@ -2118,6 +2608,25 @@ class GUI {
2118
2608
  child.update();
2119
2609
  }
2120
2610
  }
2611
+ /**
2612
+ * Sets this folder as active and deactivates all other folders
2613
+ */ setActive() {
2614
+ // Only root GUI can manage active states
2615
+ if (!this.parent) return;
2616
+ // Remove active class from ALL folders in the entire GUI tree using DOM query
2617
+ const allActiveFolders = document.querySelectorAll('.lil-gui.active');
2618
+ allActiveFolders.forEach((folder)=>{
2619
+ folder.classList.remove('active');
2620
+ });
2621
+ // Add active class to this folder
2622
+ this.domElement.classList.add('active');
2623
+ }
2624
+ /**
2625
+ * Gets the currently active folder
2626
+ */ getActiveFolder() {
2627
+ if (!this.parent) return null;
2628
+ return this.parent.folders.find((folder)=>folder.domElement.classList.contains('active')) || null;
2629
+ }
2121
2630
  constructor({ parent, container, width, autoPlace = parent === undefined, title = 'Controls', id = title, closeFolders = false, touchStyles = true } = {}){
2122
2631
  this.children = [];
2123
2632
  this.controllers = [];
@@ -2139,6 +2648,8 @@ class GUI {
2139
2648
  this.$title.setAttribute('aria-expanded', "true");
2140
2649
  this.$title.setAttribute('tabindex', "0");
2141
2650
  this.$title.addEventListener('click', ()=>{
2651
+ // Set this folder as active and deactivate others
2652
+ this.setActive();
2142
2653
  this.openAnimated(this._closed);
2143
2654
  });
2144
2655
  this.$title.addEventListener('keydown', (e)=>{
@@ -2197,7 +2708,7 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
2197
2708
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2198
2709
  PERFORMANCE OF THIS SOFTWARE.
2199
2710
  ***************************************************************************** */
2200
- /* global Reflect, Promise, SuppressedError, Symbol */
2711
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
2201
2712
 
2202
2713
 
2203
2714
  function __decorate(decorators, target, key, desc) {
@@ -2353,67 +2864,74 @@ __decorate([
2353
2864
  core.property
2354
2865
  ], ViewerHelper.prototype, "targetFrameRate", null);
2355
2866
 
2356
- class Inspector extends core.Mount {
2867
+ const vert_Sprite = `
2868
+ uniform vec4 u_transform;
2869
+ uniform vec4 u_resolution;
2870
+ varying vec2 v_uv;
2871
+
2872
+ void main() {
2873
+ vec2 pos = u_transform.xy + u_transform.zw * 0.5 + position.xy * u_transform.zw;
2874
+ vec2 ndc = pos * u_resolution.zw * 2. - 1.;
2875
+ gl_Position = vec4(ndc, 0., 1.);
2876
+ v_uv = uv;
2877
+ }
2878
+ `;
2879
+ const frag_Sprite = `
2880
+ uniform sampler2D u_texture;
2881
+ varying vec2 v_uv;
2882
+
2883
+ void main() {
2884
+ gl_FragColor = texture2D(u_texture, v_uv);
2885
+ }
2886
+ `;
2887
+ class Inspector extends core.Component {
2357
2888
  onLoad() {
2358
2889
  const { width, height } = this.viewer;
2359
- this._scene = new three.Scene();
2360
- this._camera = new three.OrthographicCamera(0, width, height, 0, -1, 1);
2890
+ this._spriteUniforms.u_resolution.value.set(width, height, 1 / width, 1 / height);
2891
+ this._sprite = new three.Mesh(new three.PlaneGeometry(1, 1, 1, 1), new three.ShaderMaterial({
2892
+ side: three.DoubleSide,
2893
+ vertexShader: vert_Sprite,
2894
+ fragmentShader: frag_Sprite,
2895
+ uniforms: this._spriteUniforms
2896
+ }));
2897
+ this._sprite.frustumCulled = false;
2898
+ this._camera.viewport = new three.Vector4(0, 0, 256, 256);
2361
2899
  this._gui = new GUI({
2362
2900
  width: 310,
2363
2901
  title: "Inspector"
2364
2902
  }).close();
2903
+ this._tree = this._gui.addSceneTree(this.viewer.scene);
2365
2904
  this._gui.addFolder("Viewer").close().hide();
2366
2905
  this._gui.addFolder("Component").close().hide();
2367
2906
  this._gui.addFolder("Material").close().hide();
2368
2907
  this._gui.addFolder("Other").close().hide();
2369
2908
  this._inspect(new ViewerHelper(this.viewer));
2370
- this._addSprite();
2371
2909
  }
2372
2910
  onDestroy() {
2911
+ if (this._tree) {
2912
+ this._tree.destroy();
2913
+ }
2373
2914
  this._gui.destroy();
2374
2915
  this._refCntMap.clear();
2375
2916
  this._targetMap.clear();
2376
2917
  }
2377
2918
  update(dt) {
2378
2919
  this._gui.update();
2920
+ if (this._tree) {
2921
+ this._tree.update();
2922
+ }
2379
2923
  this._updateFolders();
2380
2924
  }
2381
2925
  resize(width, height) {
2382
- this._camera.left = 0;
2383
- this._camera.right = width;
2384
- this._camera.top = height;
2385
- this._camera.bottom = 0;
2386
- this._camera.updateProjectionMatrix();
2387
- }
2388
- _addSprite() {
2389
- const viewer = this.viewer;
2390
- this._sprite = viewer.add(three.Sprite, {
2391
- parent: this._scene,
2392
- scale: new three.Vector3(256, 256, 1),
2393
- position: new three.Vector3(viewer.width / 2, viewer.height / 2),
2394
- visible: false
2395
- });
2396
- }
2397
- _renderScene() {
2398
- const { renderer } = this.viewer;
2399
- const autoClearDepth = renderer.autoClearDepth;
2400
- const autoClearColor = renderer.autoClearColor;
2401
- renderer.autoClearDepth = true;
2402
- renderer.autoClearColor = false;
2403
- renderer.render(this._scene, this._camera);
2404
- renderer.autoClearDepth = autoClearDepth;
2405
- renderer.autoClearColor = autoClearColor;
2406
- return renderer.domElement;
2926
+ this._spriteUniforms.u_resolution.value.set(width, height, 1 / width, 1 / height);
2407
2927
  }
2408
2928
  _renderSprite(texture, w, h) {
2409
- this._sprite.visible = true;
2410
- this._sprite.scale.set(w, h, 1);
2411
- this._sprite.position.set(w / 2, this._camera.top - h / 2, 0);
2412
- this._sprite.material.map = texture;
2413
- this._sprite.material.needsUpdate = true;
2414
- const dom = this._renderScene();
2415
- this._sprite.visible = false;
2416
- return dom;
2929
+ const resolution = this._spriteUniforms.u_resolution.value;
2930
+ this._camera.viewport.set(0, resolution.y - h, w, h);
2931
+ this._spriteUniforms.u_transform.value.set(0, resolution.y - h, w, h);
2932
+ this._spriteUniforms.u_texture.value = texture;
2933
+ this.viewer.render(null, this._sprite, this._camera, 0, 0);
2934
+ return this.viewer.canvas;
2417
2935
  }
2418
2936
  _updateFolders() {
2419
2937
  const refCntMap = this._refCntMap;
@@ -2422,8 +2940,14 @@ class Inspector extends core.Mount {
2422
2940
  if (refCntMap.get(v) === undefined) refCntMap.set(v, 1);
2423
2941
  };
2424
2942
  refCntMap.forEach((_, k, map)=>map.set(k, -1));
2425
- this.viewer.traverseMaterials(setState);
2426
- this.viewer.traverseComponents(setState);
2943
+ const { scene, componentManager } = this.viewer;
2944
+ scene.traverse((item)=>{
2945
+ if (item.material) {
2946
+ if (Array.isArray(item.material)) item.material.forEach(setState);
2947
+ else setState(item.material);
2948
+ }
2949
+ });
2950
+ componentManager.traverseComponents(setState);
2427
2951
  refCntMap.forEach((v, k, map)=>{
2428
2952
  if (v === 1) {
2429
2953
  this._inspect(k);
@@ -2499,12 +3023,16 @@ class Inspector extends core.Mount {
2499
3023
  this._addGUI(folder, this._getPropertiesList(value), target, k);
2500
3024
  }
2501
3025
  if (Array.isArray(value)) {
2502
- this._addGUI(folder, [
2503
- value.map((_, i)=>[
2504
- i.toString(),
2505
- {}
2506
- ])
2507
- ], value, k);
3026
+ if (prop.flat) {
3027
+ value.forEach((v)=>this._addGUI(folder, this._getPropertiesList(v), v, v.constructor.name));
3028
+ } else {
3029
+ this._addGUI(folder, [
3030
+ value.map((_, i)=>[
3031
+ i.toString(),
3032
+ {}
3033
+ ])
3034
+ ], value, k);
3035
+ }
2508
3036
  } else {
2509
3037
  const type = typeof value;
2510
3038
  let ins = null;
@@ -2542,11 +3070,20 @@ class Inspector extends core.Mount {
2542
3070
  }
2543
3071
  }
2544
3072
  constructor(...args){
2545
- super(...args);
2546
- this._refCntMap = new Map();
2547
- this._targetMap = new Map();
3073
+ super(...args), this._camera = new three.Camera(), this._sprite = null, this._spriteUniforms = {
3074
+ u_texture: {
3075
+ value: null
3076
+ },
3077
+ u_transform: {
3078
+ value: new three.Vector4()
3079
+ },
3080
+ u_resolution: {
3081
+ value: new three.Vector4()
3082
+ }
3083
+ }, this._refCntMap = new Map(), this._targetMap = new Map();
2548
3084
  }
2549
3085
  }
3086
+ Inspector.viewport = new three.Vector4();
2550
3087
  function targetName(target) {
2551
3088
  return target.name || target.constructor.name || target.type;
2552
3089
  }
@@ -2564,8 +3101,14 @@ const materialProperties = {
2564
3101
  transparent: {
2565
3102
  order: 2
2566
3103
  },
3104
+ depthWrite: {
3105
+ order: 3
3106
+ },
3107
+ depthTest: {
3108
+ order: 4
3109
+ },
2567
3110
  side: {
2568
- order: 3,
3111
+ order: 5,
2569
3112
  value: {
2570
3113
  FrontSide: 0,
2571
3114
  BackSide: 1,
@@ -2573,12 +3116,10 @@ const materialProperties = {
2573
3116
  }
2574
3117
  },
2575
3118
  color: {
2576
- order: 4,
2577
- dir: "diffuse"
3119
+ order: 6
2578
3120
  },
2579
3121
  opacity: {
2580
- order: 5,
2581
- dir: "diffuse",
3122
+ order: 7,
2582
3123
  min: 0,
2583
3124
  max: 1,
2584
3125
  step: 0.01
@@ -2924,7 +3465,7 @@ var Stats$1 = function() {
2924
3465
  };
2925
3466
  };
2926
3467
 
2927
- class Stats extends core.Mount {
3468
+ class Stats extends core.Component {
2928
3469
  onLoad() {
2929
3470
  this._stats.addPanel(this._dcPanel);
2930
3471
  this._stats.addPanel(this._texPanel);
@@ -2945,36 +3486,10 @@ class Stats extends core.Mount {
2945
3486
  this._stats.update();
2946
3487
  }
2947
3488
  constructor(...args){
2948
- super(...args);
2949
- this._stats = new Stats$1();
2950
- this._dcPanel = new Panel('DC', '#ff8', '#221');
2951
- this._triPanel = new Panel("TRI", '#ff8', '#221');
2952
- this._texPanel = new Panel('TEX', '#ff8', '#221');
2953
- this._prgPanel = new Panel('PRG', '#ff8', '#221');
2954
- }
2955
- }
2956
-
2957
- class BoxProjectionHelper extends core.Mount {
2958
- onLoad() {
2959
- this._box3 = new three.Box3();
2960
- this._target = this.viewer.mount(core.BoxProjection);
2961
- this._helper = this.viewer.add(new three.Box3Helper(this._box3));
2962
- }
2963
- onEnable() {
2964
- this._helper.visible = true;
2965
- }
2966
- onDisable() {
2967
- this._helper.visible = false;
2968
- }
2969
- update(dt) {
2970
- const { center, boxMin, boxMax } = this._target;
2971
- this._box3.min.copy(center).add(boxMin);
2972
- this._box3.max.copy(center).add(boxMax);
2973
- this._helper.updateMatrixWorld();
3489
+ super(...args), this._stats = new Stats$1(), this._dcPanel = new Panel('DC', '#ff8', '#221'), this._triPanel = new Panel("TRI", '#ff8', '#221'), this._texPanel = new Panel('TEX', '#ff8', '#221'), this._prgPanel = new Panel('PRG', '#ff8', '#221');
2974
3490
  }
2975
3491
  }
2976
3492
 
2977
- exports.BoxProjectionHelper = BoxProjectionHelper;
2978
3493
  exports.GUI = GUI;
2979
3494
  exports.Inspector = Inspector;
2980
3495
  exports.Stats = Stats;