├── .gitignore ├── inspector-icon.png ├── devtools.html ├── playcanvas-devtools ├── images │ ├── physics-menu.jpg │ ├── entity-picker.jpg │ ├── ministats-menu.jpg │ ├── print-graph-menu.jpg │ ├── entity-picker-menu.jpg │ ├── physics-expanded-menu.jpg │ ├── preview-20200715-152807.jpg │ ├── devtools-playcanvas-button.jpg │ ├── print-graph-entities-only.jpg │ └── print-graph-with-filter-model.jpg ├── pc-devtools.js ├── injector.js ├── debug-physics.js ├── playcanvas-extras.js └── dat.gui.min.js ├── inspector-panel.html ├── devtools.js ├── manifest.json ├── LICENSE ├── package.json ├── README.md └── inspector-panel.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /inspector-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/inspector-icon.png -------------------------------------------------------------------------------- /devtools.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /playcanvas-devtools/images/physics-menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/playcanvas-devtools/images/physics-menu.jpg -------------------------------------------------------------------------------- /playcanvas-devtools/images/entity-picker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/playcanvas-devtools/images/entity-picker.jpg -------------------------------------------------------------------------------- /playcanvas-devtools/images/ministats-menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/playcanvas-devtools/images/ministats-menu.jpg -------------------------------------------------------------------------------- /playcanvas-devtools/images/print-graph-menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/playcanvas-devtools/images/print-graph-menu.jpg -------------------------------------------------------------------------------- /playcanvas-devtools/images/entity-picker-menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/playcanvas-devtools/images/entity-picker-menu.jpg -------------------------------------------------------------------------------- /playcanvas-devtools/images/physics-expanded-menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/playcanvas-devtools/images/physics-expanded-menu.jpg -------------------------------------------------------------------------------- /playcanvas-devtools/images/preview-20200715-152807.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/playcanvas-devtools/images/preview-20200715-152807.jpg -------------------------------------------------------------------------------- /playcanvas-devtools/images/devtools-playcanvas-button.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/playcanvas-devtools/images/devtools-playcanvas-button.jpg -------------------------------------------------------------------------------- /playcanvas-devtools/images/print-graph-entities-only.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/playcanvas-devtools/images/print-graph-entities-only.jpg -------------------------------------------------------------------------------- /playcanvas-devtools/images/print-graph-with-filter-model.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/playcanvas/playcanvas-inspector/HEAD/playcanvas-devtools/images/print-graph-with-filter-model.jpg -------------------------------------------------------------------------------- /inspector-panel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /devtools.js: -------------------------------------------------------------------------------- 1 | chrome.devtools.panels.create("PlayCanvas", 2 | "inspector-icon.png", 3 | "inspector-panel.html", 4 | function (panel) { 5 | } 6 | ); 7 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PlayCanvas Inspector", 3 | "version": "1.0", 4 | "description": "Inspect published PlayCanvas applications", 5 | "manifest_version": 2, 6 | "minimum_chrome_version": "83.0", 7 | "devtools_page": "devtools.html", 8 | "permissions": [ 9 | "activeTab", 10 | "tabs", 11 | "http://*/*", 12 | "https://*/*" 13 | ], 14 | "web_accessible_resources": [ 15 | "playcanvas-devtools/injector.js", 16 | "playcanvas-devtools/pc-devtools.js", 17 | "playcanvas-devtools/dat.gui.min.js", 18 | "playcanvas-devtools/debug-physics.js", 19 | "playcanvas-devtools/playcanvas-extras.js" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 PlayCanvas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@playcanvas/inspector", 3 | "version": "1.0.0", 4 | "author": "PlayCanvas ", 5 | "homepage": "https://playcanvas.com", 6 | "description": "Chrome extension for inspecting published PlayCanvas apps", 7 | "keywords": [ 8 | "playcanvas", 9 | "webgl", 10 | "chrome" 11 | ], 12 | "license": "MIT", 13 | "bugs": { 14 | "url": "https://github.com/playcanvas/playcanvas-inspector/issues" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/playcanvas/playcanvas-inspector.git" 19 | }, 20 | "eslintConfig": { 21 | "extends": "@playcanvas/eslint-config", 22 | "globals": { 23 | "dat": "readonly", 24 | "chrome": "readonly", 25 | "pc": "readonly", 26 | "pcDevtools": "readonly" 27 | } 28 | }, 29 | "eslintIgnore": [ 30 | "playcanvas-devtools/dat.gui.min.js", 31 | "playcanvas-devtools/playcanvas-extras.js" 32 | ], 33 | "devDependencies": { 34 | "@playcanvas/eslint-config": "^1.0.16", 35 | "eslint": "^8.8.0" 36 | }, 37 | "scripts": { 38 | "lint": "eslint ." 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PlayCanvas Inspector 2 | 3 | Chrome extension for inspecting published PlayCanvas apps. 4 | 5 | ![Preview](playcanvas-devtools/images/preview-20200715-152807.jpg) 6 | 7 | ## Installation 8 | 9 | 1. In Chrome, navigate to chrome://extensions/ 10 | 2. In the top left of the tab, hit 'Load unpacked' 11 | 3. Select the root folder of your clone of the playcanvas-inspector repo 12 | 13 | ## Enabling the Inspector 14 | 15 | Open Chrome DevTools and select the PlayCanvas tab. Press the 'Add devtools' button to add the debug menu to the app. 16 | 17 | ![DevTools button](playcanvas-devtools/images/devtools-playcanvas-button.jpg) 18 | 19 | Note that the Inspector will not activate if the PlayCanvas app is contained within an iframe. Apps published to the https://playcanv.as domain are wrapped in an iframe. For example, this is the link for a PlayCanvas app: 20 | 21 | https://playcanv.as/p/2OlkUaxF/ 22 | 23 | The same app without the iframe requires you to add a `/e` (which stands for embed) to the URL: 24 | 25 | https://playcanv.as/e/p/2OlkUaxF/ 26 | 27 | The Inspector will now be able to activate. 28 | 29 | ## Available Tools 30 | 31 | ### Mini Stats 32 | Shows the CPU, GPU and total frame time in ms. Can be enabled/disabled via the menu. 33 | 34 | ![Mini Stats menu](playcanvas-devtools/images/ministats-menu.jpg) 35 | 36 | ### Physics debug renderer 37 | Render physics volumes in the scene. Requires the script to be added to the scene first by clicking on `addPhysicsDebug`. 38 | 39 | ![Physics menu](playcanvas-devtools/images/physics-menu.jpg) 40 | ![Physics menu expanded](playcanvas-devtools/images/physics-expanded-menu.jpg) 41 | 42 | ### Print scene graph 43 | This will print out the scene hierarchy to the console to see the current state is. Really useful if you are adding/removing entities at runtime. 44 | 45 | ![Print graph menu](playcanvas-devtools/images/print-graph-menu.jpg) 46 | 47 | `entitiesOnly` will only print nodes that are entities (no meshInstances) 48 | `enabledNodesOnly` will filter out disabled nodes from the print out 49 | `printPaths` will print out the hierarchy paths of each node which makes it easier to modify the entity on the console 50 | 51 | e.g. 52 | ``` 53 | var e = pc.app.root.findByPath('some/path/to/entity'); 54 | e.enabled = false; 55 | ``` 56 | 57 | ![Graph entities console](playcanvas-devtools/images/print-graph-entities-only.jpg) 58 | 59 | `withFilter` allows you to add use the conditional in the filterString to print out where `node` represents the node to filter. 60 | 61 | e.g. 62 | Set the `filterString` to `node.model` will on print nodes with a model component. 63 | 64 | ![Graph filter with node.model console](playcanvas-devtools/images/print-graph-with-filter-model.jpg) 65 | 66 | ### Entity picker 67 | Allows you to middle click or touch on any object in the scene and print the details to the console. Useful for finding where entities are in the hierarchy and investigating the current prosperities on said entity. The hierarchy path is also printed to make easier to directly modify the entity on the console. 68 | 69 | e.g. 70 | ``` 71 | var e = pc.app.root.findByPath('some/path/to/entity'); 72 | e.enabled = false; 73 | ``` 74 | 75 | ![Entity picker menu](playcanvas-devtools/images/entity-picker-menu.jpg) 76 | ![Entity picker console](playcanvas-devtools/images/entity-picker.jpg) 77 | 78 | The camera list should be set to camera that is used for the current view. 79 | -------------------------------------------------------------------------------- /inspector-panel.js: -------------------------------------------------------------------------------- 1 | function createElement(type, parent, innerText) { 2 | const el = document.createElement(type); 3 | if (innerText) { 4 | el.innerText = innerText; 5 | } 6 | parent.appendChild(el); 7 | return el; 8 | } 9 | 10 | chrome.devtools.inspectedWindow.eval( 11 | "pc.version", 12 | function (result, isException) { 13 | if (isException) { 14 | console.log("The page is not using PlayCanvas"); 15 | } else { 16 | createElement('p', document.body, 'Engine Version:\t' + result); 17 | } 18 | } 19 | ); 20 | 21 | chrome.devtools.inspectedWindow.eval( 22 | "pc.revision", 23 | function (result, isException) { 24 | if (isException) { 25 | console.log("The page is not using PlayCanvas"); 26 | } else { 27 | createElement('p', document.body, 'Engine Revision:\t' + result); 28 | } 29 | } 30 | ); 31 | 32 | const code = [ 33 | 'function getComponentStats() {', 34 | ' let systems = pc.app.systems.list;', 35 | ' let results = [];', 36 | ' systems.forEach(system => {', 37 | ' let components = pc.app.root.findComponents(system.id);', 38 | ' let enabled = components.filter(component => {', 39 | ' return component.enabled && component.entity.enabled;', 40 | ' }).length;', 41 | ' results.push({', 42 | ' name: system.id,', 43 | ' enabled: enabled,', 44 | ' total: components.length', 45 | ' });', 46 | ' });', 47 | ' return results;', 48 | '}', 49 | '', 50 | 'getComponentStats();' 51 | ].join('\n'); 52 | 53 | chrome.devtools.inspectedWindow.eval( 54 | code, 55 | function (result, isException) { 56 | if (isException) { 57 | console.log("The page is not using PlayCanvas"); 58 | } else { 59 | const table = createElement('table', document.body); 60 | let row = createElement('tr', table); 61 | createElement('th', row, 'Component'); 62 | createElement('th', row, 'Enabled'); 63 | createElement('th', row, 'Total'); 64 | 65 | result.forEach((system) => { 66 | if (system.total > 0) { 67 | row = createElement('tr', table); 68 | createElement('td', row, system.name); 69 | createElement('td', row, system.enabled); 70 | createElement('td', row, system.total); 71 | } 72 | }); 73 | } 74 | } 75 | ); 76 | 77 | var onDocumentLoaded = function () { 78 | // Handler when the DOM is fully loaded 79 | var injectorUrl = chrome.runtime.getURL('playcanvas-devtools/injector.js'); 80 | 81 | // Getting the base URL so we can inject the other scripts 82 | var baseUrl = injectorUrl.replace('injector.js', ''); 83 | 84 | // Override the url to load from for the injector script 85 | chrome.devtools.inspectedWindow.eval("window.__overrideurl__ = '" + baseUrl + "';"); 86 | var injectorCode = "(function(){var a=document.createElement('script');a.src='" + injectorUrl + "';document.head.appendChild(a);})();"; 87 | var addDevtoolsButton = document.getElementById("add-devtools-button"); 88 | addDevtoolsButton.onclick = function () { 89 | chrome.devtools.inspectedWindow.eval(injectorCode); 90 | chrome.devtools.inspectedWindow.eval("console.log('Added PlayCanvas Devtools');"); 91 | }; 92 | }; 93 | 94 | if ( 95 | document.readyState === "complete" || 96 | (document.readyState !== "loading" && !document.documentElement.doScroll) 97 | ) { 98 | onDocumentLoaded(); 99 | } else { 100 | document.addEventListener("DOMContentLoaded", onDocumentLoaded); 101 | } 102 | -------------------------------------------------------------------------------- /playcanvas-devtools/pc-devtools.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var pcDevtools = {}; 3 | 4 | pcDevtools.init = function () { 5 | var app = pc.Application.getApplication(); 6 | 7 | this.app = app; 8 | 9 | // Create a frame buffer picker with a resolution of 1024x1024 10 | this.picker.picker = new pc.Picker(this.app, 1024, 1024); 11 | app.mouse.on(pc.EVENT_MOUSEDOWN, this.picker.onSelectMouse, this.picker); 12 | if (app.touch) { 13 | app.touch.on(pc.EVENT_TOUCHSTART, this.picker.onSelectTouch, this.picker); 14 | } 15 | }; 16 | 17 | pcDevtools.getPathToEntity = function (node) { 18 | var path = node.name; 19 | while (node.parent && node.parent !== pcDevtools.app.root) { 20 | path = node.parent.name + '/' + path; 21 | node = node.parent; 22 | } 23 | 24 | return path; 25 | }; 26 | 27 | 28 | pcDevtools.graphPrinter = {}; 29 | 30 | pcDevtools.graphPrinter.enabledNodesOnly = false; 31 | pcDevtools.graphPrinter.showPaths = false; 32 | 33 | pcDevtools.graphPrinter.withFilter = function (node, path, filterString) { 34 | var i; 35 | var indentStr = ""; 36 | 37 | for (i = 0; i < node.graphDepth; ++i) { 38 | indentStr += " "; 39 | } 40 | 41 | var shouldPrint = true; 42 | if (filterString && filterString.length > 0) { 43 | // eslint-disable-next-line no-eval 44 | shouldPrint = eval(filterString); 45 | } 46 | 47 | // Make the text grey if it is disabled 48 | var color = ''; 49 | if (!node.enabled) { 50 | if (this.enabledNodesOnly) { 51 | shouldPrint = false; 52 | } 53 | color = 'color: #7f8c8d'; 54 | } 55 | 56 | if (path.length > 0) { 57 | path += '/' + node.name; 58 | } else if (node !== pcDevtools.app.root) { 59 | path += node.name; 60 | } 61 | 62 | if (shouldPrint && node !== pcDevtools.app.root) { 63 | var str = '%c' + indentStr + node.name; 64 | if (this.showPaths) { 65 | str += ' [' + path + ']'; 66 | } 67 | console.log(str, color); 68 | } 69 | 70 | var children = node.children; 71 | for (i = 0; i < children.length; ++i) { 72 | this.withFilter(children[i], path, filterString); 73 | } 74 | }; 75 | 76 | pcDevtools.picker = {}; 77 | pcDevtools.picker.enabled = false; 78 | pcDevtools.picker.cameraPath = ""; 79 | 80 | pcDevtools.picker.onSelect = function (x, y) { 81 | if (this.enabled) { 82 | var app = pcDevtools.app; 83 | var camera = app.root.findByPath(this.cameraPath).camera; 84 | 85 | console.log('Camera used is: ' + this.cameraPath); 86 | 87 | var canvas = app.graphicsDevice.canvas; 88 | var canvasWidth = parseInt(canvas.clientWidth, 10); 89 | var canvasHeight = parseInt(canvas.clientHeight, 10); 90 | 91 | var scene = app.scene; 92 | var picker = this.picker; 93 | 94 | picker.prepare(camera, scene); 95 | 96 | // Map the mouse coordinates into picker coordinates and 97 | // query the selection 98 | var selected = picker.getSelection( 99 | Math.floor(x * (picker.width / canvasWidth)), 100 | Math.floor(y * (picker.height / canvasHeight)) 101 | ); 102 | 103 | if (selected.length > 0) { 104 | // Get the graph node used by the selected mesh instance 105 | var entity = selected[0] ? selected[0].node : null; 106 | 107 | // Bubble up the hierarchy until we find an actual Entity 108 | while (!(entity instanceof pc.Entity) && entity !== null) { 109 | entity = entity.parent; 110 | } 111 | 112 | // Print it out to console and get the path to it 113 | if (entity) { 114 | console.log(entity); 115 | var path = pcDevtools.getPathToEntity(entity); 116 | console.log(path); 117 | } 118 | } 119 | 120 | console.log('Finished picking'); 121 | } 122 | }; 123 | 124 | pcDevtools.picker.onSelectMouse = function (evt) { 125 | if (evt.button == pc.MOUSEBUTTON_MIDDLE) { 126 | this.onSelect(evt.x, evt.y); 127 | } 128 | }; 129 | 130 | pcDevtools.picker.onSelectTouch = function (evt) { 131 | this.onSelect(evt.touches[0].x, evt.touches[0].y); 132 | evt.event.preventDefault(); 133 | }; 134 | 135 | 136 | pcDevtools.debugEntityName = '__devtools__'; 137 | pcDevtools.addScriptTypeToDebugEntity = function (scriptName, data) { 138 | var app = pcDevtools.app; 139 | var debugEntity = app.root.findByName(this.debugEntityName); 140 | if (!debugEntity) { 141 | debugEntity = new pc.Entity(); 142 | debugEntity.addComponent('script'); 143 | app.root.addChild(debugEntity); 144 | } 145 | 146 | var scriptInstance = debugEntity.script[scriptName]; 147 | if (!scriptInstance) { 148 | scriptInstance = debugEntity.script.create(scriptName, { 149 | attributes: data 150 | }); 151 | } 152 | 153 | return scriptInstance; 154 | }; 155 | 156 | window.pcDevtools = pcDevtools; 157 | })(); 158 | -------------------------------------------------------------------------------- /playcanvas-devtools/injector.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-use-before-define, block-scoped-var 2 | if (!__addedDebugTools__) { 3 | var __addedDebugTools__ = false; 4 | (function () { 5 | if (!__addedDebugTools__) { 6 | var baseUrl; 7 | if (window.__overrideurl__) { 8 | baseUrl = window.__overrideurl__; 9 | console.log('Using url override ' + baseUrl); 10 | } else { 11 | baseUrl = 'https://yaustar.github.io/playcanvas-devtools/'; 12 | console.log('Using @yaustar GitHub'); 13 | } 14 | 15 | var scriptFilenames = [ 16 | 'dat.gui.min.js', 17 | 'playcanvas-extras.js', 18 | 'debug-physics.js', 19 | 'pc-devtools.js' 20 | ]; 21 | 22 | var app = pc.Application.getApplication(); 23 | var debugPhysicsFolder, entityPickerFolder; 24 | var datgui; 25 | 26 | var dummyObj = {}; 27 | dummyObj.addPhysicsDebugger = function () { 28 | if (debugPhysicsFolder) { 29 | datgui.removeFolder(debugPhysicsFolder); 30 | } 31 | 32 | // Add the physics debugger 33 | var debugPhysics = pcDevtools.addScriptTypeToDebugEntity('__debugPhysics__', { 34 | drawShapes: false, 35 | opacity: 0.5, 36 | castShadows: false 37 | }); 38 | 39 | debugPhysicsFolder = datgui.addFolder('Physics'); 40 | debugPhysicsFolder.add(dummyObj, 'addPhysicsDebugger'); 41 | debugPhysicsFolder.add(debugPhysics, 'drawShapes'); 42 | debugPhysicsFolder.add(debugPhysics, 'opacity', 0, 1); 43 | debugPhysicsFolder.add(debugPhysics, 'castShadows'); 44 | }; 45 | 46 | // Add scene graph printer 47 | dummyObj.printGraph = {}; 48 | dummyObj.printGraph.filterString = ''; 49 | dummyObj.printGraph.printWithFilter = function () { 50 | console.log('\n=== Print Graph with filter ' + dummyObj.printGraph.filterString + ' ==='); 51 | pcDevtools.graphPrinter.withFilter(app.root, '', dummyObj.printGraph.filterString); 52 | }; 53 | 54 | dummyObj.printGraph.printEntitiesOnly = function () { 55 | console.log('\n=== Print Graph entities only ==='); 56 | pcDevtools.graphPrinter.withFilter(app.root, '', 'node instanceof pc.Entity'); 57 | }; 58 | 59 | Object.defineProperty(dummyObj.printGraph, 'enabledNodesOnly', { 60 | get: function () { 61 | return pcDevtools.graphPrinter.enabledNodesOnly; 62 | }, 63 | set: function (value) { 64 | pcDevtools.graphPrinter.enabledNodesOnly = value; 65 | } 66 | }); 67 | 68 | Object.defineProperty(dummyObj.printGraph, 'printPaths', { 69 | get: function () { 70 | return pcDevtools.graphPrinter.showPaths; 71 | }, 72 | set: function (value) { 73 | pcDevtools.graphPrinter.showPaths = value; 74 | } 75 | }); 76 | 77 | 78 | dummyObj.picker = {}; 79 | 80 | Object.defineProperty(dummyObj.picker, 'enabled', { 81 | get: function () { 82 | return pcDevtools.picker.enabled; 83 | }, 84 | set: function (value) { 85 | pcDevtools.picker.enabled = value; 86 | } 87 | }); 88 | 89 | Object.defineProperty(dummyObj.picker, 'camera', { 90 | get: function () { 91 | return pcDevtools.picker.cameraPath; 92 | }, 93 | set: function (value) { 94 | pcDevtools.picker.cameraPath = value; 95 | } 96 | }); 97 | 98 | dummyObj.picker.cameraDropdownController = null; 99 | dummyObj.picker.refreshActiveCameras = function () { 100 | if (dummyObj.picker.cameraDropdownController) { 101 | entityPickerFolder.remove(dummyObj.picker.cameraDropdownController); 102 | } 103 | 104 | var cameras = app.systems.camera.cameras; 105 | var cameraPaths = []; 106 | var i; 107 | for (i = 0; i < cameras.length; ++i) { 108 | var camera = cameras[i]; 109 | if (camera.entity.enabled) { 110 | cameraPaths.push(pcDevtools.getPathToEntity(camera.entity)); 111 | } 112 | } 113 | 114 | if (cameraPaths.length > 0) { 115 | dummyObj.picker.camera = cameraPaths[0]; 116 | } 117 | 118 | dummyObj.picker.cameraDropdownController = entityPickerFolder.add(dummyObj.picker, 'camera', cameraPaths); 119 | }; 120 | 121 | 122 | var callback = function () { 123 | console.log('All PlayCanvas Debug Tool scripts loaded'); 124 | 125 | pcDevtools.init(); 126 | 127 | // Load the ministats 128 | var ministats = new pc.MiniStats(app); 129 | 130 | // Load dat gui 131 | datgui = new dat.GUI(); 132 | var ministatsFolder = datgui.addFolder('Mini Stats'); 133 | ministatsFolder.add(ministats, 'enabled'); 134 | 135 | debugPhysicsFolder = datgui.addFolder('Physics'); 136 | debugPhysicsFolder.add(dummyObj, 'addPhysicsDebugger'); 137 | 138 | var printGraphFolder = datgui.addFolder('Print Graph'); 139 | printGraphFolder.add(dummyObj.printGraph, 'filterString'); 140 | printGraphFolder.add(dummyObj.printGraph, 'printWithFilter'); 141 | printGraphFolder.add(dummyObj.printGraph, 'printEntitiesOnly'); 142 | printGraphFolder.add(dummyObj.printGraph, 'enabledNodesOnly'); 143 | printGraphFolder.add(dummyObj.printGraph, 'printPaths'); 144 | 145 | entityPickerFolder = datgui.addFolder('Entity Picker'); 146 | entityPickerFolder.add(dummyObj.picker, 'enabled'); 147 | entityPickerFolder.add(dummyObj.picker, 'refreshActiveCameras'); 148 | 149 | dummyObj.picker.refreshActiveCameras(); 150 | }; 151 | 152 | var scriptsLoaded = 0; 153 | for (var i = 0; i < scriptFilenames.length; ++i) { 154 | var imported = document.createElement('script'); 155 | imported.src = baseUrl + scriptFilenames[i]; 156 | // eslint-disable-next-line no-loop-func 157 | imported.onload = function () { 158 | scriptsLoaded += 1; 159 | if (scriptsLoaded == scriptFilenames.length) { 160 | callback(); 161 | } 162 | }; 163 | document.head.appendChild(imported); 164 | } 165 | 166 | __addedDebugTools__ = true; 167 | } 168 | })(); 169 | } 170 | -------------------------------------------------------------------------------- /playcanvas-devtools/debug-physics.js: -------------------------------------------------------------------------------- 1 | var DebugPhysics = pc.createScript('__debugPhysics__'); 2 | 3 | DebugPhysics.attributes.add('drawShapes', { 4 | type: 'boolean', 5 | default: false, 6 | title: 'Draw Shapes', 7 | description: 'Draw representations of physics collision shapes' 8 | }); 9 | DebugPhysics.attributes.add('opacity', { 10 | type: 'number', 11 | default: 0.5, 12 | min: 0, 13 | max: 1, 14 | title: 'Opacity', 15 | description: 'Opacity of physics collision shapes' 16 | }); 17 | DebugPhysics.attributes.add('castShadows', { 18 | type: 'boolean', 19 | default: true, 20 | title: 'Cast Shadows', 21 | description: 'Cast shadows from physics collision shapes' 22 | }); 23 | 24 | // initialize code called once per entity 25 | DebugPhysics.prototype.initialize = function () { 26 | // Handle attribute change events 27 | this.on('attr:castShadows', function (value, prev) { 28 | this.debugRoot.children.forEach(function (child) { 29 | child.model.castShadows = value; 30 | }); 31 | }, this); 32 | this.on('attr:opacity', function (value, prev) { 33 | this.debugRoot.children.forEach(function (child) { 34 | child.model.meshInstances.forEach(function (meshInstance) { 35 | var material = meshInstance.material; 36 | material.opacity = value; 37 | material.update(); 38 | }); 39 | }, this); 40 | }, this); 41 | 42 | this.debugRoot = new pc.Entity('Physics Debug Root'); 43 | this.app.root.addChild(this.debugRoot); 44 | 45 | // Handle script enable/disable events 46 | this.on('enable', function () { 47 | this.debugRoot = new pc.Entity('Physics Debug Root'); 48 | this.app.root.addChild(this.debugRoot); 49 | }); 50 | 51 | this.on('disable', function () { 52 | var collisionComponents = this.app.root.findComponents('collision'); 53 | collisionComponents.forEach(function (collision) { 54 | if (collision.hasOwnProperty('_debugShape')) { 55 | delete collision._debugShape; 56 | } 57 | }); 58 | this.debugRoot.destroy(); 59 | }); 60 | }; 61 | 62 | DebugPhysics.prototype.createModel = function (mesh, material) { 63 | var node = new pc.GraphNode(); 64 | var meshInstance = new pc.MeshInstance(node, mesh, material); 65 | var model = new pc.Model(); 66 | model.graph = node; 67 | model.meshInstances = [meshInstance]; 68 | return model; 69 | }; 70 | 71 | DebugPhysics.prototype.postUpdate = function (dt) { 72 | // For any existing debug shapes, mark them as not updated (yet) 73 | this.debugRoot.children.forEach(function (child) { 74 | child.updated = false; 75 | }); 76 | 77 | if (this.drawShapes) { 78 | // For each collision component, update its debug shape (creating one 79 | // if one does not exist) 80 | var collisionComponents = this.app.root.findComponents('collision'); 81 | collisionComponents.forEach(function (collision) { 82 | if (collision.enabled && collision.entity.enabled) { 83 | var deleteShape = false; 84 | 85 | // If the type or shape of the collision components has changed, recreate the visuals 86 | if (collision._debugShape) { 87 | if (collision._debugShape._collisionType !== collision.type) { 88 | deleteShape = true; 89 | } else { 90 | switch (collision.type) { 91 | case 'box': 92 | if (!collision._debugShape._halfExents.equals(collision.halfExtents)) { 93 | deleteShape = true; 94 | } 95 | break; 96 | case 'cone': 97 | case 'cylinder': 98 | case 'capsule': 99 | if (collision._debugShape._height !== collision.height || collision._debugShape._radius !== collision.radius) { 100 | deleteShape = true; 101 | } 102 | break; 103 | case 'sphere': 104 | if (collision._debugShape._radius !== collision.radius) { 105 | deleteShape = true; 106 | } 107 | break; 108 | } 109 | } 110 | } 111 | 112 | if (deleteShape) { 113 | collision._debugShape.destroy(); 114 | delete collision._debugShape; 115 | } 116 | 117 | // No accompanying debug render shape for this collision component so create one 118 | if (!collision._debugShape) { 119 | var material = new pc.StandardMaterial(); 120 | material.diffuse.set(Math.random(), Math.random(), Math.random()); 121 | material.opacity = this.opacity; 122 | material.blendType = pc.BLEND_NORMAL; 123 | material.update(); 124 | 125 | var debugShape = new pc.Entity(); 126 | 127 | var mesh; 128 | switch (collision.type) { 129 | case 'box': 130 | mesh = pc.createBox(this.app.graphicsDevice, { 131 | halfExtents: collision.halfExtents 132 | }); 133 | debugShape._halfExents = collision.halfExtents.clone(); 134 | break; 135 | case 'cone': 136 | mesh = pc.createCone(this.app.graphicsDevice, { 137 | height: collision.height, 138 | radius: collision.radius 139 | }); 140 | debugShape._height = collision.height; 141 | debugShape._radius = collision.radius; 142 | break; 143 | case 'cylinder': 144 | mesh = pc.createCylinder(this.app.graphicsDevice, { 145 | height: collision.height, 146 | radius: collision.radius 147 | }); 148 | debugShape._height = collision.height; 149 | debugShape._radius = collision.radius; 150 | break; 151 | case 'sphere': 152 | mesh = pc.createSphere(this.app.graphicsDevice, { 153 | radius: collision.radius 154 | }); 155 | debugShape._radius = collision.radius; 156 | break; 157 | case 'capsule': 158 | mesh = pc.createCapsule(this.app.graphicsDevice, { 159 | height: collision.height, 160 | radius: collision.radius 161 | }); 162 | debugShape._height = collision.height; 163 | debugShape._radius = collision.radius; 164 | break; 165 | } 166 | 167 | if (mesh) { 168 | debugShape.addComponent('model', { 169 | castShadows: this.castShadows, 170 | type: 'asset' 171 | }); 172 | debugShape.model.model = this.createModel(mesh, material); 173 | } 174 | 175 | this.debugRoot.addChild(debugShape); 176 | 177 | // Cache collision component 178 | debugShape._collision = collision; 179 | debugShape._collisionType = collision.type; 180 | collision._debugShape = debugShape; 181 | } 182 | 183 | // Use the rigid body position if we have it 184 | if (collision.entity.rigidbody) { 185 | var body = collision.entity.rigidbody.data.body; 186 | if (body) { 187 | var t = body.getWorldTransform(); 188 | 189 | var p = t.getOrigin(); 190 | var q = t.getRotation(); 191 | collision._debugShape.setPosition(p.x(), p.y(), p.z()); 192 | collision._debugShape.setRotation(q.x(), q.y(), q.z(), q.w()); 193 | } 194 | } else { 195 | collision._debugShape.setPosition(collision.entity.getPosition()); 196 | collision._debugShape.setRotation(collision.entity.getRotation()); 197 | } 198 | 199 | collision._debugShape.updated = true; 200 | } 201 | }, this); 202 | } 203 | 204 | // If a debug shape was not updated this frame, the source collision component 205 | // isn't around any more so we can delete it 206 | this.debugRoot.children.forEach(function (child) { 207 | if (!child.updated) { 208 | delete child._collision._debugShape; 209 | delete child._collision; 210 | child.destroy(); 211 | } 212 | }); 213 | }; 214 | -------------------------------------------------------------------------------- /playcanvas-devtools/playcanvas-extras.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Playcanvas Extras v1.28.0 revision 7952233b 3 | * Copyright 2011-2020 PlayCanvas Ltd. All rights reserved. 4 | */ 5 | ;(function (root, factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define([], factory); 8 | } else if (typeof module === 'object' && module.exports) { 9 | module.exports = factory(); 10 | } else { 11 | root.pc = factory(); 12 | } 13 | }(this, function () { 14 | 15 | Object.assign(pc,function(){var m=function(d){this._frameIndex=0;this._frameTimings=[];this._timings=[];this._prevTimings=[];d.on("frameupdate",this.begin.bind(this,"update"));d.on("framerender",this.mark.bind(this,"render"));d.on("frameend",this.mark.bind(this,"other"))};Object.assign(m.prototype,{begin:function(d){this._frameIndex=this._frameTimings.length?this._frameTimings.push([d,h]):(g=this._frameTimings[this._frameIndex],g[0]=d,g[1]=h);this._frameIndex++}});Object.defineProperty(m.prototype,"timings",{get:function(){return this._timings.slice(0,-1).map(function(d){return d[1]})}}); 17 | return{CpuTimer:m}}());Object.assign(pc,function(){var m=function(d){this._gl=d.graphicsDevice.gl;this._ext=d.graphicsDevice.extDisjointTimerQuery;this._freeQueries=[];this._frameQueries=[];this._frames=[];this._timings=[];this._prevTimings=[];d.on("frameupdate",this.begin.bind(this,"update"));d.on("framerender",this.mark.bind(this,"render"));d.on("frameend",this.end.bind(this))};Object.assign(m.prototype,{begin:function(d){0=c.width&&(e=5,d+=16);f.fillText(a[k],e-h,d+g);q.push({l:h,r:n,a:g,d:l,x:e,y:d,w:m,h:r});e+=m+5}var t={};a.forEach(function(a,b){t[a]=b});this.words=a;this.wordMap=t;this.placements=q;this.texture=b;a=f.getImageData(0,0,c.width,c.height);c=b.lock();for(d=0;d-1?t.length-t.indexOf(".")-1:0}function s(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}function a(e,t,n,o,i){return o+(e-t)/(n-t)*(i-o)}function l(e,t,n,o){e.style.background="",S.each(ee,function(i){e.style.cssText+="background: "+i+"linear-gradient("+t+", "+n+" 0%, "+o+" 100%); "})}function d(e){e.style.background="",e.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}function c(e,t,n){var o=document.createElement("li");return t&&o.appendChild(t),n?e.__ul.insertBefore(o,n):e.__ul.appendChild(o),e.onResize(),o}function u(e){X.unbind(window,"resize",e.__resizeHandler),e.saveToLocalStorageIfPossible&&X.unbind(window,"unload",e.saveToLocalStorageIfPossible)}function _(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];n.innerHTML=t?n.value+"*":n.value}function h(e,t,n){if(n.__li=t,n.__gui=e,S.extend(n,{options:function(t){if(arguments.length>1){var o=n.__li.nextElementSibling;return n.remove(),f(e,n.object,n.property,{before:o,factoryArgs:[S.toArray(arguments)]})}if(S.isArray(t)||S.isObject(t)){var i=n.__li.nextElementSibling;return n.remove(),f(e,n.object,n.property,{before:i,factoryArgs:[t]})}},name:function(e){return n.__li.firstElementChild.firstElementChild.innerHTML=e,n},listen:function(){return n.__gui.listen(n),n},remove:function(){return n.__gui.remove(n),n}}),n instanceof q){var o=new Q(n.object,n.property,{min:n.__min,max:n.__max,step:n.__step});S.each(["updateDisplay","onChange","onFinishChange","step","min","max"],function(e){var t=n[e],i=o[e];n[e]=o[e]=function(){var e=Array.prototype.slice.call(arguments);return i.apply(o,e),t.apply(n,e)}}),X.addClass(t,"has-slider"),n.domElement.insertBefore(o.domElement,n.domElement.firstElementChild)}else if(n instanceof Q){var i=function(t){if(S.isNumber(n.__min)&&S.isNumber(n.__max)){var o=n.__li.firstElementChild.firstElementChild.innerHTML,i=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=f(e,n.object,n.property,{before:n.__li.nextElementSibling,factoryArgs:[n.__min,n.__max,n.__step]});return r.name(o),i&&r.listen(),r}return t};n.min=S.compose(i,n.min),n.max=S.compose(i,n.max)}else n instanceof K?(X.bind(t,"click",function(){X.fakeEvent(n.__checkbox,"click")}),X.bind(n.__checkbox,"click",function(e){e.stopPropagation()})):n instanceof Z?(X.bind(t,"click",function(){X.fakeEvent(n.__button,"click")}),X.bind(t,"mouseover",function(){X.addClass(n.__button,"hover")}),X.bind(t,"mouseout",function(){X.removeClass(n.__button,"hover")})):n instanceof $&&(X.addClass(t,"color"),n.updateDisplay=S.compose(function(e){return t.style.borderLeftColor=n.__color.toString(),e},n.updateDisplay),n.updateDisplay());n.setValue=S.compose(function(t){return e.getRoot().__preset_select&&n.isModified()&&_(e.getRoot(),!0),t},n.setValue)}function p(e,t){var n=e.getRoot(),o=n.__rememberedObjects.indexOf(t.object);if(-1!==o){var i=n.__rememberedObjectIndecesToControllers[o];if(void 0===i&&(i={},n.__rememberedObjectIndecesToControllers[o]=i),i[t.property]=t,n.load&&n.load.remembered){var r=n.load.remembered,s=void 0;if(r[e.preset])s=r[e.preset];else{if(!r[se])return;s=r[se]}if(s[o]&&void 0!==s[o][t.property]){var a=s[o][t.property];t.initialValue=a,t.setValue(a)}}}}function f(e,t,n,o){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var i=void 0;if(o.color)i=new $(t,n);else{var r=[t,n].concat(o.factoryArgs);i=ne.apply(e,r)}o.before instanceof z&&(o.before=o.before.__li),p(e,i),X.addClass(i.domElement,"c");var s=document.createElement("span");X.addClass(s,"property-name"),s.innerHTML=i.property;var a=document.createElement("div");a.appendChild(s),a.appendChild(i.domElement);var l=c(e,a,o.before);return X.addClass(l,he.CLASS_CONTROLLER_ROW),i instanceof $?X.addClass(l,"color"):X.addClass(l,H(i.getValue())),h(e,l,i),e.__controllers.push(i),i}function m(e,t){return document.location.href+"."+t}function g(e,t,n){var o=document.createElement("option");o.innerHTML=t,o.value=t,e.__preset_select.appendChild(o),n&&(e.__preset_select.selectedIndex=e.__preset_select.length-1)}function b(e,t){t.style.display=e.useLocalStorage?"block":"none"}function v(e){var t=e.__save_row=document.createElement("li");X.addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),X.addClass(t,"save-row");var n=document.createElement("span");n.innerHTML=" ",X.addClass(n,"button gears");var o=document.createElement("span");o.innerHTML="Save",X.addClass(o,"button"),X.addClass(o,"save");var i=document.createElement("span");i.innerHTML="New",X.addClass(i,"button"),X.addClass(i,"save-as");var r=document.createElement("span");r.innerHTML="Revert",X.addClass(r,"button"),X.addClass(r,"revert");var s=e.__preset_select=document.createElement("select");if(e.load&&e.load.remembered?S.each(e.load.remembered,function(t,n){g(e,n,n===e.preset)}):g(e,se,!1),X.bind(s,"change",function(){for(var t=0;t=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,n){if(e)if(A&&e.forEach&&e.forEach===A)e.forEach(t,n);else if(e.length===e.length+0){var o=void 0,i=void 0;for(o=0,i=e.length;o1?S.toArray(arguments):arguments[0];return S.each(O,function(t){if(t.litmus(e))return S.each(t.conversions,function(t,n){if(T=t.read(e),!1===L&&!1!==T)return L=T,T.conversionName=n,T.conversion=t,S.BREAK}),S.BREAK}),L},B=void 0,N={hsv_to_rgb:function(e,t,n){var o=Math.floor(e/60)%6,i=e/60-Math.floor(e/60),r=n*(1-t),s=n*(1-i*t),a=n*(1-(1-i)*t),l=[[n,a,r],[s,n,r],[r,n,a],[r,s,n],[a,r,n],[n,r,s]][o];return{r:255*l[0],g:255*l[1],b:255*l[2]}},rgb_to_hsv:function(e,t,n){var o=Math.min(e,t,n),i=Math.max(e,t,n),r=i-o,s=void 0,a=void 0;return 0===i?{h:NaN,s:0,v:0}:(a=r/i,s=e===i?(t-n)/r:t===i?2+(n-e)/r:4+(e-t)/r,(s/=6)<0&&(s+=1),{h:360*s,s:a,v:i/255})},rgb_to_hex:function(e,t,n){var o=this.hex_with_component(0,2,e);return o=this.hex_with_component(o,1,t),o=this.hex_with_component(o,0,n)},component_from_hex:function(e,t){return e>>8*t&255},hex_with_component:function(e,t,n){return n<<(B=8*t)|e&~(255<this.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!=0&&(n=Math.round(n/this.__step)*this.__step),D(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"setValue",this).call(this,n)}},{key:"min",value:function(e){return this.__min=e,this}},{key:"max",value:function(e){return this.__max=e,this}},{key:"step",value:function(e){return this.__step=e,this.__impliedStep=e,this.__precision=r(e),this}}]),t}(),Q=function(e){function t(e,n,o){function i(){l.__onFinishChange&&l.__onFinishChange.call(l,l.getValue())}function r(e){var t=d-e.clientY;l.setValue(l.getValue()+t*l.__impliedStep),d=e.clientY}function s(){X.unbind(window,"mousemove",r),X.unbind(window,"mouseup",s),i()}F(this,t);var a=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,o));a.__truncationSuspended=!1;var l=a,d=void 0;return a.__input=document.createElement("input"),a.__input.setAttribute("type","text"),X.bind(a.__input,"change",function(){var e=parseFloat(l.__input.value);S.isNaN(e)||l.setValue(e)}),X.bind(a.__input,"blur",function(){i()}),X.bind(a.__input,"mousedown",function(e){X.bind(window,"mousemove",r),X.bind(window,"mouseup",s),d=e.clientY}),X.bind(a.__input,"keydown",function(e){13===e.keyCode&&(l.__truncationSuspended=!0,this.blur(),l.__truncationSuspended=!1,i())}),a.updateDisplay(),a.domElement.appendChild(a.__input),a}return j(t,W),P(t,[{key:"updateDisplay",value:function(){return this.__input.value=this.__truncationSuspended?this.getValue():s(this.getValue(),this.__precision),D(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),q=function(e){function t(e,n,o,i,r){function s(e){e.preventDefault();var t=_.__background.getBoundingClientRect();return _.setValue(a(e.clientX,t.left,t.right,_.__min,_.__max)),!1}function l(){X.unbind(window,"mousemove",s),X.unbind(window,"mouseup",l),_.__onFinishChange&&_.__onFinishChange.call(_,_.getValue())}function d(e){var t=e.touches[0].clientX,n=_.__background.getBoundingClientRect();_.setValue(a(t,n.left,n.right,_.__min,_.__max))}function c(){X.unbind(window,"touchmove",d),X.unbind(window,"touchend",c),_.__onFinishChange&&_.__onFinishChange.call(_,_.getValue())}F(this,t);var u=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,{min:o,max:i,step:r})),_=u;return u.__background=document.createElement("div"),u.__foreground=document.createElement("div"),X.bind(u.__background,"mousedown",function(e){document.activeElement.blur(),X.bind(window,"mousemove",s),X.bind(window,"mouseup",l),s(e)}),X.bind(u.__background,"touchstart",function(e){1===e.touches.length&&(X.bind(window,"touchmove",d),X.bind(window,"touchend",c),d(e))}),X.addClass(u.__background,"slider"),X.addClass(u.__foreground,"slider-fg"),u.updateDisplay(),u.__background.appendChild(u.__foreground),u.domElement.appendChild(u.__background),u}return j(t,W),P(t,[{key:"updateDisplay",value:function(){var e=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*e+"%",D(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),Z=function(e){function t(e,n,o){F(this,t);var i=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),r=i;return i.__button=document.createElement("div"),i.__button.innerHTML=void 0===o?"Fire":o,X.bind(i.__button,"click",function(e){return e.preventDefault(),r.fire(),!1}),X.addClass(i.__button,"button"),i.domElement.appendChild(i.__button),i}return j(t,z),P(t,[{key:"fire",value:function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())}}]),t}(),$=function(e){function t(e,n){function o(e){u(e),X.bind(window,"mousemove",u),X.bind(window,"touchmove",u),X.bind(window,"mouseup",r),X.bind(window,"touchend",r)}function i(e){_(e),X.bind(window,"mousemove",_),X.bind(window,"touchmove",_),X.bind(window,"mouseup",s),X.bind(window,"touchend",s)}function r(){X.unbind(window,"mousemove",u),X.unbind(window,"touchmove",u),X.unbind(window,"mouseup",r),X.unbind(window,"touchend",r),c()}function s(){X.unbind(window,"mousemove",_),X.unbind(window,"touchmove",_),X.unbind(window,"mouseup",s),X.unbind(window,"touchend",s),c()}function a(){var e=R(this.value);!1!==e?(p.__color.__state=e,p.setValue(p.__color.toOriginal())):this.value=p.__color.toString()}function c(){p.__onFinishChange&&p.__onFinishChange.call(p,p.__color.toOriginal())}function u(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=p.__saturation_field.getBoundingClientRect(),n=e.touches&&e.touches[0]||e,o=n.clientX,i=n.clientY,r=(o-t.left)/(t.right-t.left),s=1-(i-t.top)/(t.bottom-t.top);return s>1?s=1:s<0&&(s=0),r>1?r=1:r<0&&(r=0),p.__color.v=s,p.__color.s=r,p.setValue(p.__color.toOriginal()),!1}function _(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=p.__hue_field.getBoundingClientRect(),n=1-((e.touches&&e.touches[0]||e).clientY-t.top)/(t.bottom-t.top);return n>1?n=1:n<0&&(n=0),p.__color.h=360*n,p.setValue(p.__color.toOriginal()),!1}F(this,t);var h=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n));h.__color=new I(h.getValue()),h.__temp=new I(0);var p=h;h.domElement=document.createElement("div"),X.makeSelectable(h.domElement,!1),h.__selector=document.createElement("div"),h.__selector.className="selector",h.__saturation_field=document.createElement("div"),h.__saturation_field.className="saturation-field",h.__field_knob=document.createElement("div"),h.__field_knob.className="field-knob",h.__field_knob_border="2px solid ",h.__hue_knob=document.createElement("div"),h.__hue_knob.className="hue-knob",h.__hue_field=document.createElement("div"),h.__hue_field.className="hue-field",h.__input=document.createElement("input"),h.__input.type="text",h.__input_textShadow="0 1px 1px ",X.bind(h.__input,"keydown",function(e){13===e.keyCode&&a.call(this)}),X.bind(h.__input,"blur",a),X.bind(h.__selector,"mousedown",function(){X.addClass(this,"drag").bind(window,"mouseup",function(){X.removeClass(p.__selector,"drag")})}),X.bind(h.__selector,"touchstart",function(){X.addClass(this,"drag").bind(window,"touchend",function(){X.removeClass(p.__selector,"drag")})});var f=document.createElement("div");return S.extend(h.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),S.extend(h.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:h.__field_knob_border+(h.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),S.extend(h.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),S.extend(h.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),S.extend(f.style,{width:"100%",height:"100%",background:"none"}),l(f,"top","rgba(0,0,0,0)","#000"),S.extend(h.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),d(h.__hue_field),S.extend(h.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:h.__input_textShadow+"rgba(0,0,0,0.7)"}),X.bind(h.__saturation_field,"mousedown",o),X.bind(h.__saturation_field,"touchstart",o),X.bind(h.__field_knob,"mousedown",o),X.bind(h.__field_knob,"touchstart",o),X.bind(h.__hue_field,"mousedown",i),X.bind(h.__hue_field,"touchstart",i),h.__saturation_field.appendChild(f),h.__selector.appendChild(h.__field_knob),h.__selector.appendChild(h.__saturation_field),h.__selector.appendChild(h.__hue_field),h.__hue_field.appendChild(h.__hue_knob),h.domElement.appendChild(h.__input),h.domElement.appendChild(h.__selector),h.updateDisplay(),h}return j(t,z),P(t,[{key:"updateDisplay",value:function(){var e=R(this.getValue());if(!1!==e){var t=!1;S.each(I.COMPONENTS,function(n){if(!S.isUndefined(e[n])&&!S.isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}},this),t&&S.extend(this.__color.__state,e)}S.extend(this.__temp.__state,this.__color.__state),this.__temp.a=1;var n=this.__color.v<.5||this.__color.s>.5?255:0,o=255-n;S.extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toHexString(),border:this.__field_knob_border+"rgb("+n+","+n+","+n+")"}),this.__hue_knob.style.marginTop=100*(1-this.__color.h/360)+"px",this.__temp.s=1,this.__temp.v=1,l(this.__saturation_field,"left","#fff",this.__temp.toHexString()),this.__input.value=this.__color.toString(),S.extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+o+","+o+","+o+",.7)"})}}]),t}(),ee=["-moz-","-o-","-webkit-","-ms-",""],te={load:function(e,t){var n=t||document,o=n.createElement("link");o.type="text/css",o.rel="stylesheet",o.href=e,n.getElementsByTagName("head")[0].appendChild(o)},inject:function(e,t){var n=t||document,o=document.createElement("style");o.type="text/css",o.innerHTML=e;var i=n.getElementsByTagName("head")[0];try{i.appendChild(o)}catch(e){}}},ne=function(e,t){var n=e[t];return S.isArray(arguments[2])||S.isObject(arguments[2])?new Y(e,t,arguments[2]):S.isNumber(n)?S.isNumber(arguments[2])&&S.isNumber(arguments[3])?S.isNumber(arguments[4])?new q(e,t,arguments[2],arguments[3],arguments[4]):new q(e,t,arguments[2],arguments[3]):S.isNumber(arguments[4])?new Q(e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new Q(e,t,{min:arguments[2],max:arguments[3]}):S.isString(n)?new J(e,t):S.isFunction(n)?new Z(e,t,""):S.isBoolean(n)?new K(e,t):null},oe=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)},ie=function(){function e(){F(this,e),this.backgroundElement=document.createElement("div"),S.extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear",transition:"opacity 0.2s linear"}),X.makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),S.extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition:"transform 0.2s ease-out, opacity 0.2s linear"}),document.body.appendChild(this.backgroundElement),document.body.appendChild(this.domElement);var t=this;X.bind(this.backgroundElement,"click",function(){t.hide()})}return P(e,[{key:"show",value:function(){var e=this;this.backgroundElement.style.display="block",this.domElement.style.display="block",this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)",this.layout(),S.defer(function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"})}},{key:"hide",value:function(){var e=this,t=function t(){e.domElement.style.display="none",e.backgroundElement.style.display="none",X.unbind(e.domElement,"webkitTransitionEnd",t),X.unbind(e.domElement,"transitionend",t),X.unbind(e.domElement,"oTransitionEnd",t)};X.bind(this.domElement,"webkitTransitionEnd",t),X.bind(this.domElement,"transitionend",t),X.bind(this.domElement,"oTransitionEnd",t),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"}},{key:"layout",value:function(){this.domElement.style.left=window.innerWidth/2-X.getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-X.getHeight(this.domElement)/2+"px"}}]),e}(),re=function(e){if(e&&"undefined"!=typeof window){var t=document.createElement("style");return t.setAttribute("type","text/css"),t.innerHTML=e,document.head.appendChild(t),e}}(".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2FA1D6}.dg .cr.number input[type=text]{color:#2FA1D6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2FA1D6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n");te.inject(re);var se="Default",ae=function(){try{return!!window.localStorage}catch(e){return!1}}(),le=void 0,de=!0,ce=void 0,ue=!1,_e=[],he=function e(t){var n=this,o=t||{};this.domElement=document.createElement("div"),this.__ul=document.createElement("ul"),this.domElement.appendChild(this.__ul),X.addClass(this.domElement,"dg"),this.__folders={},this.__controllers=[],this.__rememberedObjects=[],this.__rememberedObjectIndecesToControllers=[],this.__listening=[],o=S.defaults(o,{closeOnTop:!1,autoPlace:!0,width:e.DEFAULT_WIDTH}),o=S.defaults(o,{resizable:o.autoPlace,hideable:o.autoPlace}),S.isUndefined(o.load)?o.load={preset:se}:o.preset&&(o.load.preset=o.preset),S.isUndefined(o.parent)&&o.hideable&&_e.push(this),o.resizable=S.isUndefined(o.parent)&&o.resizable,o.autoPlace&&S.isUndefined(o.scrollable)&&(o.scrollable=!0);var i=ae&&"true"===localStorage.getItem(m(this,"isLocal")),r=void 0,s=void 0;if(Object.defineProperties(this,{parent:{get:function(){return o.parent}},scrollable:{get:function(){return o.scrollable}},autoPlace:{get:function(){return o.autoPlace}},closeOnTop:{get:function(){return o.closeOnTop}},preset:{get:function(){return n.parent?n.getRoot().preset:o.load.preset},set:function(e){n.parent?n.getRoot().preset=e:o.load.preset=e,E(this),n.revert()}},width:{get:function(){return o.width},set:function(e){o.width=e,w(n,e)}},name:{get:function(){return o.name},set:function(e){o.name=e,s&&(s.innerHTML=o.name)}},closed:{get:function(){return o.closed},set:function(t){o.closed=t,o.closed?X.addClass(n.__ul,e.CLASS_CLOSED):X.removeClass(n.__ul,e.CLASS_CLOSED),this.onResize(),n.__closeButton&&(n.__closeButton.innerHTML=t?e.TEXT_OPEN:e.TEXT_CLOSED)}},load:{get:function(){return o.load}},useLocalStorage:{get:function(){return i},set:function(e){ae&&(i=e,e?X.bind(window,"unload",r):X.unbind(window,"unload",r),localStorage.setItem(m(n,"isLocal"),e))}}}),S.isUndefined(o.parent)){if(this.closed=o.closed||!1,X.addClass(this.domElement,e.CLASS_MAIN),X.makeSelectable(this.domElement,!1),ae&&i){n.useLocalStorage=!0;var a=localStorage.getItem(m(this,"gui"));a&&(o.load=JSON.parse(a))}this.__closeButton=document.createElement("div"),this.__closeButton.innerHTML=e.TEXT_CLOSED,X.addClass(this.__closeButton,e.CLASS_CLOSE_BUTTON),o.closeOnTop?(X.addClass(this.__closeButton,e.CLASS_CLOSE_TOP),this.domElement.insertBefore(this.__closeButton,this.domElement.childNodes[0])):(X.addClass(this.__closeButton,e.CLASS_CLOSE_BOTTOM),this.domElement.appendChild(this.__closeButton)),X.bind(this.__closeButton,"click",function(){n.closed=!n.closed})}else{void 0===o.closed&&(o.closed=!0);var l=document.createTextNode(o.name);X.addClass(l,"controller-name"),s=c(n,l);X.addClass(this.__ul,e.CLASS_CLOSED),X.addClass(s,"title"),X.bind(s,"click",function(e){return e.preventDefault(),n.closed=!n.closed,!1}),o.closed||(this.closed=!1)}o.autoPlace&&(S.isUndefined(o.parent)&&(de&&(ce=document.createElement("div"),X.addClass(ce,"dg"),X.addClass(ce,e.CLASS_AUTO_PLACE_CONTAINER),document.body.appendChild(ce),de=!1),ce.appendChild(this.domElement),X.addClass(this.domElement,e.CLASS_AUTO_PLACE)),this.parent||w(n,o.width)),this.__resizeHandler=function(){n.onResizeDebounced()},X.bind(window,"resize",this.__resizeHandler),X.bind(this.__ul,"webkitTransitionEnd",this.__resizeHandler),X.bind(this.__ul,"transitionend",this.__resizeHandler),X.bind(this.__ul,"oTransitionEnd",this.__resizeHandler),this.onResize(),o.resizable&&y(this),r=function(){ae&&"true"===localStorage.getItem(m(n,"isLocal"))&&localStorage.setItem(m(n,"gui"),JSON.stringify(n.getSaveObject()))},this.saveToLocalStorageIfPossible=r,o.parent||function(){var e=n.getRoot();e.width+=1,S.defer(function(){e.width-=1})}()};he.toggleHide=function(){ue=!ue,S.each(_e,function(e){e.domElement.style.display=ue?"none":""})},he.CLASS_AUTO_PLACE="a",he.CLASS_AUTO_PLACE_CONTAINER="ac",he.CLASS_MAIN="main",he.CLASS_CONTROLLER_ROW="cr",he.CLASS_TOO_TALL="taller-than-window",he.CLASS_CLOSED="closed",he.CLASS_CLOSE_BUTTON="close-button",he.CLASS_CLOSE_TOP="close-top",he.CLASS_CLOSE_BOTTOM="close-bottom",he.CLASS_DRAG="drag",he.DEFAULT_WIDTH=245,he.TEXT_CLOSED="Close Controls",he.TEXT_OPEN="Open Controls",he._keydownHandler=function(e){"text"===document.activeElement.type||72!==e.which&&72!==e.keyCode||he.toggleHide()},X.bind(window,"keydown",he._keydownHandler,!1),S.extend(he.prototype,{add:function(e,t){return f(this,e,t,{factoryArgs:Array.prototype.slice.call(arguments,2)})},addColor:function(e,t){return f(this,e,t,{color:!0})},remove:function(e){this.__ul.removeChild(e.__li),this.__controllers.splice(this.__controllers.indexOf(e),1);var t=this;S.defer(function(){t.onResize()})},destroy:function(){if(this.parent)throw new Error("Only the root GUI should be removed with .destroy(). For subfolders, use gui.removeFolder(folder) instead.");this.autoPlace&&ce.removeChild(this.domElement);var e=this;S.each(this.__folders,function(t){e.removeFolder(t)}),X.unbind(window,"keydown",he._keydownHandler,!1),u(this)},addFolder:function(e){if(void 0!==this.__folders[e])throw new Error('You already have a folder in this GUI by the name "'+e+'"');var t={name:e,parent:this};t.autoPlace=this.autoPlace,this.load&&this.load.folders&&this.load.folders[e]&&(t.closed=this.load.folders[e].closed,t.load=this.load.folders[e]);var n=new he(t);this.__folders[e]=n;var o=c(this,n.domElement);return X.addClass(o,"folder"),n},removeFolder:function(e){this.__ul.removeChild(e.domElement.parentElement),delete this.__folders[e.name],this.load&&this.load.folders&&this.load.folders[e.name]&&delete this.load.folders[e.name],u(e);var t=this;S.each(e.__folders,function(t){e.removeFolder(t)}),S.defer(function(){t.onResize()})},open:function(){this.closed=!1},close:function(){this.closed=!0},hide:function(){this.domElement.style.display="none"},show:function(){this.domElement.style.display=""},onResize:function(){var e=this.getRoot();if(e.scrollable){var t=X.getOffset(e.__ul).top,n=0;S.each(e.__ul.childNodes,function(t){e.autoPlace&&t===e.__save_row||(n+=X.getHeight(t))}),window.innerHeight-t-20GUI\'s constructor:\n\n \n\n
\n\n Automatically save\n values to localStorage on exit.\n\n
The values saved to localStorage will\n override those passed to dat.GUI\'s constructor. This makes it\n easier to work incrementally, but localStorage is fragile,\n and your friends may not see the same values you do.\n\n
\n\n
\n\n'),this.parent)throw new Error("You can only call remember on a top level GUI.");var e=this;S.each(Array.prototype.slice.call(arguments),function(t){0===e.__rememberedObjects.length&&v(e),-1===e.__rememberedObjects.indexOf(t)&&e.__rememberedObjects.push(t)}),this.autoPlace&&w(this,this.width)},getRoot:function(){for(var e=this;e.parent;)e=e.parent;return e},getSaveObject:function(){var e=this.load;return e.closed=this.closed,this.__rememberedObjects.length>0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=x(this)),e.folders={},S.each(this.__folders,function(t,n){e.folders[n]=t.getSaveObject()}),e},save:function(){this.load.remembered||(this.load.remembered={}),this.load.remembered[this.preset]=x(this),_(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[se]=x(this,!0)),this.load.remembered[e]=x(this),this.preset=e,g(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){S.each(this.__controllers,function(t){this.getRoot().load.remembered?p(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())},this),S.each(this.__folders,function(e){e.revert(e)}),e||_(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&C(this.__listening)},updateDisplay:function(){S.each(this.__controllers,function(e){e.updateDisplay()}),S.each(this.__folders,function(e){e.updateDisplay()})}});var pe={Color:I,math:N,interpret:R},fe={Controller:z,BooleanController:K,OptionController:Y,StringController:J,NumberController:W,NumberControllerBox:Q,NumberControllerSlider:q,FunctionController:Z,ColorController:$},me={dom:X},ge={GUI:he},be=he,ve={color:pe,controllers:fe,dom:me,gui:ge,GUI:be};e.color=pe,e.controllers=fe,e.dom=me,e.gui=ge,e.GUI=be,e.default=ve,Object.defineProperty(e,"__esModule",{value:!0})}); 14 | --------------------------------------------------------------------------------