Parcourir la source

Merge pull request #2 from BabylonJS/master

Merge latest
Dave Solares il y a 4 ans
Parent
commit
53bb0fb2db
100 fichiers modifiés avec 73343 ajouts et 15050 suppressions
  1. 13 0
      .editorconfig
  2. 1 0
      .gitignore
  3. 27 0
      .vscode/launch.json
  4. 1 0
      Playground/frame.html
  5. 1 0
      Playground/full.html
  6. 2 1
      Playground/index-local.html
  7. 1 0
      Playground/index.html
  8. 1 0
      Playground/index.js
  9. 21 29
      Playground/libs/babylon.manager.d.ts
  10. 11 11
      Playground/libs/babylon.manager.js
  11. BIN
      Playground/scenes/cubeMorph_8target.glb
  12. 4 0
      Playground/src/components/commandBarComponent.tsx
  13. 59 2
      Tools/Config/config.json
  14. 1 2
      Viewer/package.json
  15. 1 1
      Viewer/src/templating/templateManager.ts
  16. 4 2
      Viewer/tests/validation/validation.js
  17. 435 238
      dist/preview release/babylon.d.ts
  18. 2 2
      dist/preview release/babylon.js
  19. 1392 430
      dist/preview release/babylon.max.js
  20. 1 1
      dist/preview release/babylon.max.js.map
  21. 907 485
      dist/preview release/babylon.module.d.ts
  22. 435 238
      dist/preview release/documentation.d.ts
  23. 1 1
      dist/preview release/glTF2Interface/package.json
  24. 52 52
      dist/preview release/gui/babylon.gui.js
  25. 1 1
      dist/preview release/gui/babylon.gui.js.map
  26. 2 2
      dist/preview release/gui/package.json
  27. 1162 0
      dist/preview release/guiEditor/babylon.guiEditor.d.ts
  28. 30 0
      dist/preview release/guiEditor/babylon.guiEditor.js
  29. 46461 0
      dist/preview release/guiEditor/babylon.guiEditor.max.js
  30. 1 0
      dist/preview release/guiEditor/babylon.guiEditor.max.js.map
  31. 2466 0
      dist/preview release/guiEditor/babylon.guiEditor.module.d.ts
  32. 27 0
      dist/preview release/guiEditor/package.json
  33. 15 0
      dist/preview release/guiEditor/readme-es6.md
  34. 1 0
      dist/preview release/guiEditor/readme.md
  35. 6 6
      dist/preview release/inspector/babylon.inspector.bundle.js
  36. 12566 12577
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  37. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  38. 58 35
      dist/preview release/inspector/babylon.inspector.d.ts
  39. 223 179
      dist/preview release/inspector/babylon.inspector.module.d.ts
  40. 7 7
      dist/preview release/inspector/package.json
  41. 17 18
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  42. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  43. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  44. 17 18
      dist/preview release/loaders/babylon.glTFFileLoader.js
  45. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  46. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  47. 17 18
      dist/preview release/loaders/babylonjs.loaders.js
  48. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  49. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  50. 3 3
      dist/preview release/loaders/package.json
  51. 2 2
      dist/preview release/materialsLibrary/package.json
  52. 448 14
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  53. 6 6
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  54. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  55. 1002 79
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  56. 2 2
      dist/preview release/nodeEditor/package.json
  57. 1 1
      dist/preview release/package.json
  58. 1 1
      dist/preview release/packagesSizeBaseLine.json
  59. 2 2
      dist/preview release/postProcessesLibrary/package.json
  60. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  61. 0 1
      dist/preview release/serializers/babylon.glTF2Serializer.js
  62. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.js.map
  63. 0 1
      dist/preview release/serializers/babylonjs.serializers.js
  64. 1 1
      dist/preview release/serializers/babylonjs.serializers.js.map
  65. 3 3
      dist/preview release/serializers/package.json
  66. 907 485
      dist/preview release/viewer/babylon.module.d.ts
  67. 83 63
      dist/preview release/viewer/babylon.viewer.js
  68. 3 3
      dist/preview release/viewer/babylon.viewer.max.js
  69. 23 4
      dist/preview release/what's new.md
  70. 20 12
      gui/src/3D/controls/control3D.ts
  71. 3 0
      gui/src/3D/controls/index.ts
  72. 367 0
      gui/src/3D/controls/touchButton3D.ts
  73. 364 0
      gui/src/3D/controls/touchHolographicButton.ts
  74. 81 0
      gui/src/3D/controls/touchMeshButton3D.ts
  75. 52 0
      gui/src/3D/gui3DManager.ts
  76. 1 0
      guiEditor/README-ES6.md
  77. 18 0
      guiEditor/README.md
  78. 3 0
      guiEditor/imgs/downArrow.svg
  79. 43 0
      guiEditor/public/index-local.html
  80. 42 0
      guiEditor/public/index.html
  81. 116 0
      guiEditor/public/index.js
  82. 211 0
      guiEditor/src/components/guiList/guiList.scss
  83. 89 0
      guiEditor/src/components/guiList/guiListComponent.tsx
  84. 20 0
      guiEditor/src/components/log/log.scss
  85. 63 0
      guiEditor/src/components/log/logComponent.tsx
  86. 798 0
      guiEditor/src/components/propertyTab/propertyTab.scss
  87. 251 0
      guiEditor/src/components/propertyTab/propertyTabComponent.tsx
  88. 182 0
      guiEditor/src/diagram/guiNode.ts
  89. 113 0
      guiEditor/src/diagram/properties/genericNodePropertyComponent.tsx
  90. 7 0
      guiEditor/src/diagram/properties/propertyComponentProps.ts
  91. 541 0
      guiEditor/src/diagram/workbench.tsx
  92. 452 0
      guiEditor/src/diagram/workbenchCanvas.scss
  93. 44 0
      guiEditor/src/globalState.ts
  94. 80 0
      guiEditor/src/guiEditor.ts
  95. 54 0
      guiEditor/src/guiNodeTools.ts
  96. 1 0
      guiEditor/src/index.ts
  97. 9 0
      guiEditor/src/legacy/legacy.ts
  98. 344 0
      guiEditor/src/main.scss
  99. 26 0
      guiEditor/src/nodeLocationInfo.ts
  100. 0 0
      guiEditor/src/portal.tsx

+ 13 - 0
.editorconfig

@@ -0,0 +1,13 @@
+# editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = crlf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = false
+
+[*.md]
+trim_trailing_whitespace = false

+ 1 - 0
.gitignore

@@ -212,3 +212,4 @@ ktx2Decoder/dist/
 # Symlinks
 # Symlinks
 inspector/src/sharedUiComponents/**/*
 inspector/src/sharedUiComponents/**/*
 nodeEditor/src/sharedUiComponents/**/*
 nodeEditor/src/sharedUiComponents/**/*
+guiEditor/src/sharedUiComponents/**/*

+ 27 - 0
.vscode/launch.json

@@ -40,6 +40,19 @@
             "runtimeArgs": [
             "runtimeArgs": [
                 "--enable-unsafe-es3-apis"
                 "--enable-unsafe-es3-apis"
             ]
             ]
+        }, 
+        {
+            "name": "Launch GUI Editor (Chrome)",
+            "type": "chrome",
+            "request": "launch",
+            "url": "http://localhost:1338/guiEditor/public/index-local.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "preLaunchTask": "run",
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis"
+            ]
         },     
         },     
         {
         {
             "name": "Launch Viewer (Chrome)",
             "name": "Launch Viewer (Chrome)",
@@ -107,6 +120,20 @@
                 "--enable-unsafe-es3-apis"
                 "--enable-unsafe-es3-apis"
             ]
             ]
         },
         },
+        {
+            "name": "Launch playground (Chrome Canary)",
+            "type": "chrome",
+            "request": "launch",
+            "url": "http://localhost:1338/Playground/index-local.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "preLaunchTask": "run",
+            "userDataDir": "${workspaceRoot}/.tempChromeCanaryProfileForDebug",
+            "runtimeExecutable": "C:/Users/alexis/AppData/Local/Google/Chrome SxS/Application/Chrome.exe",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis"
+            ]
+        },
         { 
         { 
             "name": "Launch playground (Edge)",
             "name": "Launch playground (Edge)",
             "type": "edge",
             "type": "edge",

+ 1 - 0
Playground/frame.html

@@ -39,6 +39,7 @@
         <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js"></script>
         <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js"></script>
+        <script src="https://preview.babylonjs.com/guiEditor/babylon.guiEditor.js"></script>
         <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
         <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
         <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
         <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
         <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
         <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>

+ 1 - 0
Playground/full.html

@@ -39,6 +39,7 @@
         <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js"></script>
         <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js"></script>
+        <script src="https://preview.babylonjs.com/guiEditor/babylon.guiEditor.js"></script>
         <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
         <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
         <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
         <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
         <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
         <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>

+ 2 - 1
Playground/index-local.html

@@ -82,7 +82,8 @@
                         wasmUASTCToRGBA_UNORM: GetAbsoluteUrl("../dist/preview%20release/ktx2Transcoders/uastc_rgba32_unorm.wasm"),
                         wasmUASTCToRGBA_UNORM: GetAbsoluteUrl("../dist/preview%20release/ktx2Transcoders/uastc_rgba32_unorm.wasm"),
                         wasmUASTCToRGBA_SRGB: GetAbsoluteUrl("../dist/preview%20release/ktx2Transcoders/uastc_rgba32_srgb.wasm"),
                         wasmUASTCToRGBA_SRGB: GetAbsoluteUrl("../dist/preview%20release/ktx2Transcoders/uastc_rgba32_srgb.wasm"),
                         jsMSCTranscoder: GetAbsoluteUrl("../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.js"),
                         jsMSCTranscoder: GetAbsoluteUrl("../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.js"),
-                        wasmMSCTranscoder: GetAbsoluteUrl("../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.wasm")
+                        wasmMSCTranscoder: GetAbsoluteUrl("../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.wasm"),
+                        wasmZSTDDecoder: GetAbsoluteUrl("../dist/preview%20release/zstddec.wasm"),
                     };
                     };
                 });
                 });
         </script>
         </script>

+ 1 - 0
Playground/index.html

@@ -45,6 +45,7 @@
         <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
         <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
         <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js"></script>
         <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js"></script>
+        <script src="https://preview.babylonjs.com/guiEditor/babylon.guiEditor.js"></script>
 
 
          <!-- Extensions -->
          <!-- Extensions -->
          <script
          <script

+ 1 - 0
Playground/index.js

@@ -5,6 +5,7 @@ var Versions = {
         "https://preview.babylonjs.com/gui/babylon.gui.min.js",
         "https://preview.babylonjs.com/gui/babylon.gui.min.js",
         "https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js",
         "https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js",
         "https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js",
         "https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js",
+        "https://preview.babylonjs.com/guiEditor/babylon.guiEditor.js",
         "https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js",
         "https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js",
         "https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js",
         "https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js",
         "https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js",
         "https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js",

+ 21 - 29
Playground/libs/babylon.manager.d.ts

@@ -198,6 +198,8 @@ declare module BABYLON {
         static GetTransformNode(scene: BABYLON.Scene, name: string): BABYLON.TransformNode;
         static GetTransformNode(scene: BABYLON.Scene, name: string): BABYLON.TransformNode;
         /** Gets the specified transform node by id from scene. */
         /** Gets the specified transform node by id from scene. */
         static GetTransformNodeByID(scene: BABYLON.Scene, id: string): BABYLON.TransformNode;
         static GetTransformNodeByID(scene: BABYLON.Scene, id: string): BABYLON.TransformNode;
+        /** Gets the transform node child detail mesh. */
+        static GetTransformDetailMesh(transform: TransformNode): BABYLON.AbstractMesh;
         /** Gets the transform node primitive meshes. */
         /** Gets the transform node primitive meshes. */
         static GetPrimitiveMeshes(transform: TransformNode): BABYLON.AbstractMesh[];
         static GetPrimitiveMeshes(transform: TransformNode): BABYLON.AbstractMesh[];
         /** Gets the specified transform node primary layer index. */
         /** Gets the specified transform node primary layer index. */
@@ -1475,19 +1477,19 @@ declare module BABYLON {
         /** Set animation target property */
         /** Set animation target property */
         static SetAnimationTargetProperty(animation: BABYLON.Animation, property: string): void;
         static SetAnimationTargetProperty(animation: BABYLON.Animation, property: string): void;
         /** Gets the float "result" as the sampled key frame value for the specfied animation track. */
         /** Gets the float "result" as the sampled key frame value for the specfied animation track. */
-        static SampleAnimationFloat(animation: BABYLON.Animation, frame: number): number;
+        static SampleAnimationFloat(animation: BABYLON.Animation, time: number): number;
         /** Set the passed vector2 "result" as the sampled key frame value for the specfied animation track. */
         /** Set the passed vector2 "result" as the sampled key frame value for the specfied animation track. */
-        static SampleAnimationVector2(animation: BABYLON.Animation, frame: number): BABYLON.Vector2;
+        static SampleAnimationVector2(animation: BABYLON.Animation, time: number): BABYLON.Vector2;
         /** Set the passed vector3 "result" as the sampled key frame value for the specfied animation track. */
         /** Set the passed vector3 "result" as the sampled key frame value for the specfied animation track. */
-        static SampleAnimationVector3(animation: BABYLON.Animation, frame: number): BABYLON.Vector3;
+        static SampleAnimationVector3(animation: BABYLON.Animation, time: number): BABYLON.Vector3;
         /** Set the passed quaternion "result" as the sampled key frame value for the specfied animation track. */
         /** Set the passed quaternion "result" as the sampled key frame value for the specfied animation track. */
-        static SampleAnimationQuaternion(animation: BABYLON.Animation, frame: number): BABYLON.Quaternion;
+        static SampleAnimationQuaternion(animation: BABYLON.Animation, time: number): BABYLON.Quaternion;
         /** Set the passed matrix "result" as the sampled key frame value for the specfied animation track. */
         /** Set the passed matrix "result" as the sampled key frame value for the specfied animation track. */
-        static SampleAnimationMatrix(animation: BABYLON.Animation, frame: number): BABYLON.Matrix;
+        static SampleAnimationMatrix(animation: BABYLON.Animation, time: number): BABYLON.Matrix;
         /** Creates a targeted float animation for tweening.  */
         /** Creates a targeted float animation for tweening.  */
-        static CreateFloatAnimation(name: string, targetProperty: string, startValue: number, endValue: number, frameRate?: number, loopMode?: number): BABYLON.Animation;
+        static CreateTweenAnimation(name: string, targetProperty: string, startValue: number, endValue: number, frameRate?: number, loopMode?: number): BABYLON.Animation;
         /** Gets the last key frame index value. */
         /** Gets the last key frame index value. */
-        static GetLastKeyFrameIndex(animation: BABYLON.Animation): number;
+        static GetLastKeyFrameValue(animation: BABYLON.Animation): number;
         /** Private internal frame interpolation helper */
         /** Private internal frame interpolation helper */
         private static InterpolateAnimation;
         private static InterpolateAnimation;
         /** Initialize default shader material properties */
         /** Initialize default shader material properties */
@@ -2293,20 +2295,24 @@ declare module BABYLON {
         heightOffset: number;
         heightOffset: number;
         angularSpeed: number;
         angularSpeed: number;
         updatePosition: boolean;
         updatePosition: boolean;
+        updateRotation: boolean;
         distanceEpsilon: number;
         distanceEpsilon: number;
         velocityEpsilon: number;
         velocityEpsilon: number;
+        offMeshVelocity: number;
         stoppingDistance: number;
         stoppingDistance: number;
+        isReady(): boolean;
         isNavigating(): boolean;
         isNavigating(): boolean;
+        isOnOffMeshLink(): boolean;
         getAgentType(): number;
         getAgentType(): number;
         getAgentState(): number;
         getAgentState(): number;
         getAgentIndex(): number;
         getAgentIndex(): number;
-        getAgentRadius(): number;
-        getAgentHeight(): number;
-        getAgentSpeed(): number;
         getAgentOffset(): number;
         getAgentOffset(): number;
         getTargetDistance(): number;
         getTargetDistance(): number;
+        getAgentParameters(): BABYLON.IAgentParameters;
+        setAgentParameters(parameters: BABYLON.IAgentParameters): void;
         protected m_agentState: number;
         protected m_agentState: number;
         protected m_agentIndex: number;
         protected m_agentIndex: number;
+        protected m_agentReady: boolean;
         protected m_agentGhost: BABYLON.TransformNode;
         protected m_agentGhost: BABYLON.TransformNode;
         protected m_agentParams: BABYLON.IAgentParameters;
         protected m_agentParams: BABYLON.IAgentParameters;
         protected m_agentRotation: BABYLON.Quaternion;
         protected m_agentRotation: BABYLON.Quaternion;
@@ -2315,8 +2321,10 @@ declare module BABYLON {
         protected m_agentQuaternion: BABYLON.Quaternion;
         protected m_agentQuaternion: BABYLON.Quaternion;
         protected m_agentDestination: BABYLON.Vector3;
         protected m_agentDestination: BABYLON.Vector3;
         protected awake(): void;
         protected awake(): void;
-        protected update(): void;
+        protected late(): void;
         protected destroy(): void;
         protected destroy(): void;
+        /** Register handler that is triggered when the agent is ready for navigation */
+        onReadyObservable: Observable<TransformNode>;
         /** Register handler that is triggered before the navigation update */
         /** Register handler that is triggered before the navigation update */
         onPreUpdateObservable: Observable<TransformNode>;
         onPreUpdateObservable: Observable<TransformNode>;
         /** Register handler that is triggered after the navigation update */
         /** Register handler that is triggered after the navigation update */
@@ -2325,13 +2333,14 @@ declare module BABYLON {
         onNavCompleteObservable: Observable<TransformNode>;
         onNavCompleteObservable: Observable<TransformNode>;
         private awakeNavigationAgent;
         private awakeNavigationAgent;
         private updateNavigationAgent;
         private updateNavigationAgent;
+        private updateAgentParameters;
         private destroyNavigationAgent;
         private destroyNavigationAgent;
         /** Move agent relative to current position. */
         /** Move agent relative to current position. */
         move(offset: BABYLON.Vector3, closetPoint?: boolean): void;
         move(offset: BABYLON.Vector3, closetPoint?: boolean): void;
         /** Teleport agent to destination point. */
         /** Teleport agent to destination point. */
         teleport(destination: BABYLON.Vector3, closetPoint?: boolean): void;
         teleport(destination: BABYLON.Vector3, closetPoint?: boolean): void;
         /** Sets agent current destination point. */
         /** Sets agent current destination point. */
-        setDestination(destination: BABYLON.Vector3, closetPoint?: boolean, resetAgent?: boolean): void;
+        setDestination(destination: BABYLON.Vector3, closetPoint?: boolean): void;
         /** Gets agent current world space velocity. */
         /** Gets agent current world space velocity. */
         getAgentVelocity(): BABYLON.Vector3;
         getAgentVelocity(): BABYLON.Vector3;
         /** Gets agent current world space velocity. */
         /** Gets agent current world space velocity. */
@@ -2664,23 +2673,6 @@ declare module BABYLON {
 
 
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Babylon window socket controller pro class (Socket.IO)
-     * @class SocketController - All rights reserved (c) 2020 Mackey Kinard
-     */
-    class SocketController {
-        /** Registers an handler for window socket connect event */
-        static RegisterOnSocketConnect(func: () => void): void;
-        /** Registers an handler for window socket disconnect event */
-        static RegisterOnSocketDisconnect(func: () => void): void;
-        /** Connects a window state socket */
-        static ConnectWindowSocket(connection: string): SocketIOClient.Socket;
-        /** Get the window state socket */
-        static GetWindowSocket(): SocketIOClient.Socket;
-    }
-}
-
-declare module BABYLON {
-    /**
      * Babylon web video player pro class (Unity Style Shuriken Particle System)
      * Babylon web video player pro class (Unity Style Shuriken Particle System)
      * @class WebVideoPlayer - All rights reserved (c) 2020 Mackey Kinard
      * @class WebVideoPlayer - All rights reserved (c) 2020 Mackey Kinard
      */
      */

Fichier diff supprimé car celui-ci est trop grand
+ 11 - 11
Playground/libs/babylon.manager.js


BIN
Playground/scenes/cubeMorph_8target.glb


+ 4 - 0
Playground/src/components/commandBarComponent.tsx

@@ -54,6 +54,10 @@ export class CommandBarComponent extends React.Component<ICommandBarComponentPro
         let activeVersion = Utilities.ReadStringFromStore("version", "Latest");
         let activeVersion = Utilities.ReadStringFromStore("version", "Latest");
         let activeEngineVersion = Utilities.ReadStringFromStore("engineVersion", "WebGL2");
         let activeEngineVersion = Utilities.ReadStringFromStore("engineVersion", "WebGL2");
 
 
+        if (location.href.indexOf("webgpu") !== -1 && !!navigator.gpu) {
+            activeEngineVersion = "WebGPU";
+        }
+
         var versionOptions = Object.keys(Versions).map(key => {
         var versionOptions = Object.keys(Versions).map(key => {
             return {
             return {
                 label: key,
                 label: key,

+ 59 - 2
Tools/Config/config.json

@@ -48,7 +48,8 @@
         "serializers",
         "serializers",
         "gui",
         "gui",
         "inspector",
         "inspector",
-        "nodeEditor"
+        "nodeEditor",
+        "guiEditor"
     ],
     ],
     "es6modules": [
     "es6modules": [
         "core",
         "core",
@@ -60,7 +61,8 @@
         "gui",
         "gui",
         "inspector",
         "inspector",
         "viewer",
         "viewer",
-        "nodeEditor"
+        "nodeEditor",
+        "guiEditor"
     ],
     ],
     "apps": [
     "apps": [
         "playground",
         "playground",
@@ -651,6 +653,61 @@
             }
             }
         }
         }
     },
     },
+    "guiEditor": {
+        "libraries": [
+            {
+                "output": "babylon.guiEditor.js",
+                "entry": "./legacy/legacy.ts"
+            }
+        ],
+        "build": {            
+            "ignoreInWorkerMode": true,
+            "ignoreInTestMode": true,
+            "mainFolder": "./guiEditor/",
+            "uncheckedLintImports": [
+                "react",
+                "react-dom",
+                "dagre",
+                "re-resizable",
+                "glTF",
+                "file-saver"
+            ],
+            "sharedUiComponents": "src/sharedUiComponents/",
+            "umd": {
+                "packageName": "babylonjs-gui-editor",
+                "webpackRoot": "GUIEDITOR",
+                "processDeclaration": {
+                    "filename": "babylon.guiEditor.module.d.ts",
+                    "moduleName": "GUIEDITOR",
+                    "importsToRemove": [],
+                    "classMap": {
+                        "babylonjs": "BABYLON",
+                        "react": "React",
+                        "@babylonjs/core": "BABYLON",
+                        "@fortawesome": false,
+                        "react-contextmenu": false
+                    }
+                }
+            },
+            "es6": {
+                "webpackBuild": true,
+                "buildDependencies": [
+                    "node_modules/re-resizable/lib/index.es5.js",
+                    "Tools/**/*"
+                ],
+                "packageName": "@babylonjs/gui-editor",
+                "readme": "dist/preview release/guiEditor/readme-es6.md",
+                "packagesFiles": [
+                    "babylon.guiEditor.max.js",
+                    "babylon.guiEditor.max.js.map",
+                    "babylon.guiEditor.module.d.ts",
+                    "readme.md"
+                ],
+                "typings": "babylon.guiEditor.module.d.ts",
+                "index": "babylon.guiEditor.max.js"
+            }
+        }
+    },
     "ktx2Decoder": {
     "ktx2Decoder": {
         "tempFileName": "babylon.ktx2Decoder.js",
         "tempFileName": "babylon.ktx2Decoder.js",
         "distFile": "/dist/preview release/babylon.ktx2Decoder.js",
         "distFile": "/dist/preview release/babylon.ktx2Decoder.js",

+ 1 - 2
Viewer/package.json

@@ -29,11 +29,10 @@
         "base64-image-loader": "^1.2.1",
         "base64-image-loader": "^1.2.1",
         "base64-inline-loader": "^1.1.1",
         "base64-inline-loader": "^1.1.1",
         "deepmerge": "~2.1.1",
         "deepmerge": "~2.1.1",
-        "handlebars": "^4.5.1",
+        "handlebars": "^4.7.6",
         "html-loader": "^0.5.5",
         "html-loader": "^0.5.5",
         "json-loader": "^0.5.7",
         "json-loader": "^0.5.7",
         "ts-loader": "^4.4.0",
         "ts-loader": "^4.4.0",
-        "uglifyjs-webpack-plugin": "^1.2.2",
         "webpack": "^4.29.3",
         "webpack": "^4.29.3",
         "webpack-cli": "^3.3.9",
         "webpack-cli": "^3.3.9",
         "webpack-dev-server": "^3.1.14"
         "webpack-dev-server": "^3.1.14"

+ 1 - 1
Viewer/src/templating/templateManager.ts

@@ -596,7 +596,7 @@ export class Template {
                             selector = this.parent.tagName;
                             selector = this.parent.tagName;
                         }
                         }
                         let binding = functionToFire.bind(this, selector);
                         let binding = functionToFire.bind(this, selector);
-                        this.parent.addEventListener(eventName, functionToFire.bind(this, selector), false);
+                        this.parent.addEventListener(eventName, binding, false);
                         this._registeredEvents.push({
                         this._registeredEvents.push({
                             htmlElement: this.parent,
                             htmlElement: this.parent,
                             eventName: eventName,
                             eventName: eventName,

+ 4 - 2
Viewer/tests/validation/validation.js

@@ -320,7 +320,8 @@ function init() {
         wasmUASTCToRGBA_UNORM: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/uastc_rgba32_unorm.wasm"),
         wasmUASTCToRGBA_UNORM: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/uastc_rgba32_unorm.wasm"),
         wasmUASTCToRGBA_SRGB: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/uastc_rgba32_srgb.wasm"),
         wasmUASTCToRGBA_SRGB: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/uastc_rgba32_srgb.wasm"),
         jsMSCTranscoder: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.js"),
         jsMSCTranscoder: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.js"),
-        wasmMSCTranscoder: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.wasm")
+        wasmMSCTranscoder: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.wasm"),
+        wasmZSTDDecoder: GetAbsoluteUrl("../../dist/preview%20release/zstddec.wasm"),
     };
     };
 
 
     BABYLON.KhronosTextureContainer2.URLConfig = {
     BABYLON.KhronosTextureContainer2.URLConfig = {
@@ -330,7 +331,8 @@ function init() {
         wasmUASTCToRGBA_UNORM: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/uastc_rgba32_unorm.wasm"),
         wasmUASTCToRGBA_UNORM: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/uastc_rgba32_unorm.wasm"),
         wasmUASTCToRGBA_SRGB: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/uastc_rgba32_srgb.wasm"),
         wasmUASTCToRGBA_SRGB: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/uastc_rgba32_srgb.wasm"),
         jsMSCTranscoder: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.js"),
         jsMSCTranscoder: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.js"),
-        wasmMSCTranscoder: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.wasm")
+        wasmMSCTranscoder: GetAbsoluteUrl("../../dist/preview%20release/ktx2Transcoders/msc_basis_transcoder.wasm"),
+        wasmZSTDDecoder: GetAbsoluteUrl("../../dist/preview%20release/zstddec.wasm"),
     };
     };
 
 
     viewerElement = document.createElement("babylon");
     viewerElement = document.createElement("babylon");

Fichier diff supprimé car celui-ci est trop grand
+ 435 - 238
dist/preview release/babylon.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 2 - 2
dist/preview release/babylon.js


Fichier diff supprimé car celui-ci est trop grand
+ 1392 - 430
dist/preview release/babylon.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/babylon.max.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 907 - 485
dist/preview release/babylon.module.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 435 - 238
dist/preview release/documentation.d.ts


+ 1 - 1
dist/preview release/glTF2Interface/package.json

@@ -1,7 +1,7 @@
 {
 {
     "name": "babylonjs-gltf2interface",
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "5.0.0-alpha.5",
+    "version": "5.0.0-alpha.6",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 52 - 52
dist/preview release/gui/babylon.gui.js

@@ -7,7 +7,7 @@
 		exports["babylonjs-gui"] = factory(require("babylonjs"));
 		exports["babylonjs-gui"] = factory(require("babylonjs"));
 	else
 	else
 		root["BABYLON"] = root["BABYLON"] || {}, root["BABYLON"]["GUI"] = factory(root["BABYLON"]);
 		root["BABYLON"] = root["BABYLON"] || {}, root["BABYLON"]["GUI"] = factory(root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_perfCounter__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
 return /******/ (function(modules) { // webpackBootstrap
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
 /******/ 	var installedModules = {};
@@ -400,7 +400,7 @@ module.exports = g;
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTextureInstrumentation", function() { return AdvancedDynamicTextureInstrumentation; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTextureInstrumentation", function() { return AdvancedDynamicTextureInstrumentation; });
-/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__);
 
 
 /**
 /**
@@ -543,7 +543,7 @@ var AdvancedDynamicTextureInstrumentation = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTexture", function() { return AdvancedDynamicTexture; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTexture", function() { return AdvancedDynamicTexture; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _controls_container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./controls/container */ "./2D/controls/container.ts");
 /* harmony import */ var _controls_container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./controls/container */ "./2D/controls/container.ts");
 /* harmony import */ var _controls_control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./controls/control */ "./2D/controls/control.ts");
 /* harmony import */ var _controls_control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./controls/control */ "./2D/controls/control.ts");
@@ -1622,7 +1622,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _textBlock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./textBlock */ "./2D/controls/textBlock.ts");
 /* harmony import */ var _textBlock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./textBlock */ "./2D/controls/textBlock.ts");
 /* harmony import */ var _image__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./image */ "./2D/controls/image.ts");
 /* harmony import */ var _image__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./image */ "./2D/controls/image.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__);
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__);
 
 
 
 
@@ -1854,7 +1854,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Checkbox", function() { return Checkbox; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Checkbox", function() { return Checkbox; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -2050,7 +2050,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorPicker", function() { return ColorPicker; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorPicker", function() { return ColorPicker; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
@@ -3456,7 +3456,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container", function() { return Container; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container", function() { return Container; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -3916,7 +3916,7 @@ babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredTypes
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control", function() { return Control; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control", function() { return Control; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -6066,7 +6066,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DisplayGrid", function() { return DisplayGrid; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DisplayGrid", function() { return DisplayGrid; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
 
 
@@ -6330,7 +6330,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
 
 
@@ -6429,7 +6429,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FocusableButton", function() { return FocusableButton; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FocusableButton", function() { return FocusableButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _button__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./button */ "./2D/controls/button.ts");
 /* harmony import */ var _button__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./button */ "./2D/controls/button.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
 
 
@@ -6538,7 +6538,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__);
 
 
 
 
@@ -6996,7 +6996,7 @@ babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__["_TypeStore"].RegisteredTypes[
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Image", function() { return Image; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Image", function() { return Image; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 
 
@@ -7992,7 +7992,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputPassword", function() { return InputPassword; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputPassword", function() { return InputPassword; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var _textWrapper__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./textWrapper */ "./2D/controls/textWrapper.ts");
 /* harmony import */ var _textWrapper__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./textWrapper */ "./2D/controls/textWrapper.ts");
 
 
@@ -8035,7 +8035,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputText", function() { return InputText; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputText", function() { return InputText; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -9124,7 +9124,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -9414,7 +9414,7 @@ babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].Registere
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLine", function() { return MultiLine; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLine", function() { return MultiLine; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _multiLinePoint__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../multiLinePoint */ "./2D/multiLinePoint.ts");
 /* harmony import */ var _multiLinePoint__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../multiLinePoint */ "./2D/multiLinePoint.ts");
@@ -9695,7 +9695,7 @@ babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].Registe
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RadioButton", function() { return RadioButton; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RadioButton", function() { return RadioButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -9918,7 +9918,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Rectangle", function() { return Rectangle; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Rectangle", function() { return Rectangle; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
 
 
@@ -10075,7 +10075,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _scrollViewerWindow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./scrollViewerWindow */ "./2D/controls/scrollViewers/scrollViewerWindow.ts");
 /* harmony import */ var _scrollViewerWindow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./scrollViewerWindow */ "./2D/controls/scrollViewers/scrollViewerWindow.ts");
 /* harmony import */ var _sliders_scrollBar__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../sliders/scrollBar */ "./2D/controls/sliders/scrollBar.ts");
 /* harmony import */ var _sliders_scrollBar__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../sliders/scrollBar */ "./2D/controls/sliders/scrollBar.ts");
 /* harmony import */ var _sliders_imageScrollBar__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../sliders/imageScrollBar */ "./2D/controls/sliders/imageScrollBar.ts");
 /* harmony import */ var _sliders_imageScrollBar__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../sliders/imageScrollBar */ "./2D/controls/sliders/imageScrollBar.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__);
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__);
 
 
 
 
@@ -11706,7 +11706,7 @@ var SelectionPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BaseSlider", function() { return BaseSlider; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BaseSlider", function() { return BaseSlider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -12068,7 +12068,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../measure */ "./2D/measure.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../measure */ "./2D/measure.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
 
 
@@ -12251,7 +12251,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../measure */ "./2D/measure.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../measure */ "./2D/measure.ts");
-/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3__);
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3__);
 
 
 
 
@@ -12526,7 +12526,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../measure */ "./2D/measure.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../measure */ "./2D/measure.ts");
-/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3__);
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_3__);
 
 
 
 
@@ -12680,7 +12680,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Slider", function() { return Slider; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Slider", function() { return Slider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
 
 
@@ -12968,7 +12968,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel", function() { return StackPanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel", function() { return StackPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -13266,7 +13266,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextWrapping", function() { return TextWrapping; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextWrapping", function() { return TextWrapping; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBlock", function() { return TextBlock; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBlock", function() { return TextBlock; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -13948,7 +13948,7 @@ var TextWrapper = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ToggleButton", function() { return ToggleButton; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ToggleButton", function() { return ToggleButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _rectangle__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./rectangle */ "./2D/controls/rectangle.ts");
 /* harmony import */ var _rectangle__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./rectangle */ "./2D/controls/rectangle.ts");
 
 
@@ -14210,7 +14210,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyPropertySet", function() { return KeyPropertySet; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyPropertySet", function() { return KeyPropertySet; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VirtualKeyboard", function() { return VirtualKeyboard; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VirtualKeyboard", function() { return VirtualKeyboard; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./button */ "./2D/controls/button.ts");
 /* harmony import */ var _button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./button */ "./2D/controls/button.ts");
@@ -14605,7 +14605,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2WithInfo", function() { return Vector2WithInfo; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2WithInfo", function() { return Vector2WithInfo; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix2D", function() { return Matrix2D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix2D", function() { return Matrix2D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
 
 
@@ -14830,7 +14830,7 @@ var Matrix2D = /** @class */ (function () {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Measure", function() { return Measure; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Measure", function() { return Measure; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 
 var tmpRect = [
 var tmpRect = [
@@ -14995,7 +14995,7 @@ var Measure = /** @class */ (function () {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLinePoint", function() { return MultiLinePoint; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLinePoint", function() { return MultiLinePoint; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
 
@@ -15139,7 +15139,7 @@ var MultiLinePoint = /** @class */ (function () {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
 
@@ -15445,7 +15445,7 @@ var ValueAndUnit = /** @class */ (function () {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "XmlLoader", function() { return XmlLoader; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "XmlLoader", function() { return XmlLoader; });
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__);
 
 
 /**
 /**
@@ -15764,7 +15764,7 @@ var XmlLoader = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AbstractButton3D", function() { return AbstractButton3D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AbstractButton3D", function() { return AbstractButton3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
 
@@ -15807,7 +15807,7 @@ var AbstractButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Button3D", function() { return Button3D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Button3D", function() { return Button3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _abstractButton3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./abstractButton3D */ "./3D/controls/abstractButton3D.ts");
 /* harmony import */ var _abstractButton3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./abstractButton3D */ "./3D/controls/abstractButton3D.ts");
 /* harmony import */ var _2D_advancedDynamicTexture__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../2D/advancedDynamicTexture */ "./2D/advancedDynamicTexture.ts");
 /* harmony import */ var _2D_advancedDynamicTexture__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../2D/advancedDynamicTexture */ "./2D/advancedDynamicTexture.ts");
@@ -15988,7 +15988,7 @@ var Button3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container3D", function() { return Container3D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container3D", function() { return Container3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
 
@@ -16145,7 +16145,7 @@ var Container3D = /** @class */ (function (_super) {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control3D", function() { return Control3D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control3D", function() { return Control3D; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _vector3WithInfo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../vector3WithInfo */ "./3D/vector3WithInfo.ts");
 /* harmony import */ var _vector3WithInfo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../vector3WithInfo */ "./3D/vector3WithInfo.ts");
 
 
@@ -16557,7 +16557,7 @@ var Control3D = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderPanel", function() { return CylinderPanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderPanel", function() { return CylinderPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -16643,7 +16643,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HolographicButton", function() { return HolographicButton; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HolographicButton", function() { return HolographicButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _button3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./button3D */ "./3D/controls/button3D.ts");
 /* harmony import */ var _button3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./button3D */ "./3D/controls/button3D.ts");
-/* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Materials/standardMaterial */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Materials/standardMaterial */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var _materials_fluentMaterial__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../materials/fluentMaterial */ "./3D/materials/fluentMaterial.ts");
 /* harmony import */ var _materials_fluentMaterial__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../materials/fluentMaterial */ "./3D/materials/fluentMaterial.ts");
 /* harmony import */ var _2D_controls_stackPanel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../2D/controls/stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _2D_controls_stackPanel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../2D/controls/stackPanel */ "./2D/controls/stackPanel.ts");
@@ -17137,7 +17137,7 @@ var MeshButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlanePanel", function() { return PlanePanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlanePanel", function() { return PlanePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
@@ -17192,7 +17192,7 @@ var PlanePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScatterPanel", function() { return ScatterPanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScatterPanel", function() { return ScatterPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -17319,7 +17319,7 @@ var ScatterPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpherePanel", function() { return SpherePanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpherePanel", function() { return SpherePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -17405,7 +17405,7 @@ var SpherePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel3D", function() { return StackPanel3D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel3D", function() { return StackPanel3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
 
@@ -17530,7 +17530,7 @@ var StackPanel3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VolumeBasedPanel", function() { return VolumeBasedPanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VolumeBasedPanel", function() { return VolumeBasedPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
 
@@ -17721,7 +17721,7 @@ var VolumeBasedPanel = /** @class */ (function (_super) {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GUI3DManager", function() { return GUI3DManager; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GUI3DManager", function() { return GUI3DManager; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _controls_container3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./controls/container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _controls_container3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./controls/container3D */ "./3D/controls/container3D.ts");
 
 
@@ -17990,7 +17990,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterialDefines", function() { return FluentMaterialDefines; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterialDefines", function() { return FluentMaterialDefines; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterial", function() { return FluentMaterial; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterial", function() { return FluentMaterial; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _shaders_fluent_vertex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./shaders/fluent.vertex */ "./3D/materials/shaders/fluent.vertex.ts");
 /* harmony import */ var _shaders_fluent_vertex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./shaders/fluent.vertex */ "./3D/materials/shaders/fluent.vertex.ts");
 /* harmony import */ var _shaders_fluent_fragment__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./shaders/fluent.fragment */ "./3D/materials/shaders/fluent.fragment.ts");
 /* harmony import */ var _shaders_fluent_fragment__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./shaders/fluent.fragment */ "./3D/materials/shaders/fluent.fragment.ts");
@@ -18306,7 +18306,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentPixelShader", function() { return fluentPixelShader; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentPixelShader", function() { return fluentPixelShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 
 var name = 'fluentPixelShader';
 var name = 'fluentPixelShader';
@@ -18328,7 +18328,7 @@ var fluentPixelShader = { name: name, shader: shader };
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentVertexShader", function() { return fluentVertexShader; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentVertexShader", function() { return fluentVertexShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 
 var name = 'fluentVertexShader';
 var name = 'fluentVertexShader';
@@ -18351,7 +18351,7 @@ var fluentVertexShader = { name: name, shader: shader };
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3WithInfo", function() { return Vector3WithInfo; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3WithInfo", function() { return Vector3WithInfo; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
 
 
@@ -18665,14 +18665,14 @@ if (typeof globalObject !== "undefined") {
 
 
 /***/ }),
 /***/ }),
 
 
-/***/ "babylonjs/Misc/perfCounter":
+/***/ "babylonjs/Misc/observable":
 /*!****************************************************************************************************!*\
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
   \****************************************************************************************************/
 /*! no static exports found */
 /*! no static exports found */
 /***/ (function(module, exports) {
 /***/ (function(module, exports) {
 
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_perfCounter__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__;
 
 
 /***/ })
 /***/ })
 
 

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


+ 2 - 2
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-gui",
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "5.0.0-alpha.5",
+    "version": "5.0.0-alpha.6",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "5.0.0-alpha.5"
+        "babylonjs": "5.0.0-alpha.6"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

Fichier diff supprimé car celui-ci est trop grand
+ 1162 - 0
dist/preview release/guiEditor/babylon.guiEditor.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 30 - 0
dist/preview release/guiEditor/babylon.guiEditor.js


Fichier diff supprimé car celui-ci est trop grand
+ 46461 - 0
dist/preview release/guiEditor/babylon.guiEditor.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
dist/preview release/guiEditor/babylon.guiEditor.max.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 2466 - 0
dist/preview release/guiEditor/babylon.guiEditor.module.d.ts


+ 27 - 0
dist/preview release/guiEditor/package.json

@@ -0,0 +1,27 @@
+{
+    "author": {
+        "name": "David CATUHE"
+    },
+    "name": "babylonjs-gui-editor",
+    "description": "The Babylon.js GUI editor.",
+    "version": "5.0.0-alpha.3",
+    "repository": {
+        "type": "git",
+        "url": "https://github.com/BabylonJS/Babylon.js.git"
+    },
+    "license": "Apache-2.0",
+    "dependencies": {
+        "babylonjs": "5.0.0-alpha.3"
+    },
+    "files": [
+        "babylon.guiEditor.max.js.map",
+        "babylon.guiEditor.max.js",
+        "babylon.guiEditor.js",
+        "babylon.guiEditor.module.d.ts",
+		"readme.md",
+        "package.json"
+    ],
+    "engines": {
+        "node": "*"
+    }
+}

+ 15 - 0
dist/preview release/guiEditor/readme-es6.md

@@ -0,0 +1,15 @@
+Gui Editor es6
+
+# Babylon.js Gui Editor
+
+An extension to easily allow users to create and modify GUI for scenes.
+
+## Usage
+Currently avalible for local development by selecting "Launch GUI Editor (Chrome)"
+
+## Current Supported Features
+
+- Launch GUI editor in local dev mode.
+- Drag and drop GUI elements onto a canvas.
+- Select and move individual GUI elements.
+- Modify properties of selected GUI elements.

+ 1 - 0
dist/preview release/guiEditor/readme.md

@@ -0,0 +1 @@
+Gui Editor

Fichier diff supprimé car celui-ci est trop grand
+ 6 - 6
dist/preview release/inspector/babylon.inspector.bundle.js


Fichier diff supprimé car celui-ci est trop grand
+ 12566 - 12577
dist/preview release/inspector/babylon.inspector.bundle.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 58 - 35
dist/preview release/inspector/babylon.inspector.d.ts

@@ -113,18 +113,15 @@ declare module INSPECTOR {
 }
 }
 declare module INSPECTOR {
 declare module INSPECTOR {
     interface ILineContainerComponentProps {
     interface ILineContainerComponentProps {
-        globalState?: GlobalState;
         title: string;
         title: string;
         children: any[] | any;
         children: any[] | any;
         closed?: boolean;
         closed?: boolean;
     }
     }
     export class LineContainerComponent extends React.Component<ILineContainerComponentProps, {
     export class LineContainerComponent extends React.Component<ILineContainerComponentProps, {
         isExpanded: boolean;
         isExpanded: boolean;
-        isHighlighted: boolean;
     }> {
     }> {
         constructor(props: ILineContainerComponentProps);
         constructor(props: ILineContainerComponentProps);
         switchExpandedState(): void;
         switchExpandedState(): void;
-        componentDidMount(): void;
         renderHeader(): JSX.Element;
         renderHeader(): JSX.Element;
         render(): JSX.Element;
         render(): JSX.Element;
     }
     }
@@ -163,6 +160,15 @@ declare module INSPECTOR {
     }
     }
 }
 }
 declare module INSPECTOR {
 declare module INSPECTOR {
+    export class PropertyChangedEvent {
+        object: any;
+        property: string;
+        value: any;
+        initialValue: any;
+        allowNullValue?: boolean;
+    }
+}
+declare module INSPECTOR {
     export interface ICheckBoxLineComponentProps {
     export interface ICheckBoxLineComponentProps {
         label: string;
         label: string;
         target?: any;
         target?: any;
@@ -171,9 +177,11 @@ declare module INSPECTOR {
         onSelect?: (value: boolean) => void;
         onSelect?: (value: boolean) => void;
         onValueChanged?: () => void;
         onValueChanged?: () => void;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        disabled?: boolean;
     }
     }
     export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponentProps, {
     export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponentProps, {
         isSelected: boolean;
         isSelected: boolean;
+        isDisabled?: boolean;
     }> {
     }> {
         private static _UniqueIdSeed;
         private static _UniqueIdSeed;
         private _uniqueId;
         private _uniqueId;
@@ -181,6 +189,7 @@ declare module INSPECTOR {
         constructor(props: ICheckBoxLineComponentProps);
         constructor(props: ICheckBoxLineComponentProps);
         shouldComponentUpdate(nextProps: ICheckBoxLineComponentProps, nextState: {
         shouldComponentUpdate(nextProps: ICheckBoxLineComponentProps, nextState: {
             isSelected: boolean;
             isSelected: boolean;
+            isDisabled: boolean;
         }): boolean;
         }): boolean;
         onChange(): void;
         onChange(): void;
         render(): JSX.Element;
         render(): JSX.Element;
@@ -1462,7 +1471,6 @@ declare module INSPECTOR {
 }
 }
 declare module INSPECTOR {
 declare module INSPECTOR {
     interface ICommonControlPropertyGridComponentProps {
     interface ICommonControlPropertyGridComponentProps {
-        globalState: GlobalState;
         control: BABYLON.GUI.Control;
         control: BABYLON.GUI.Control;
         lockObject: LockObject;
         lockObject: LockObject;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
@@ -1562,7 +1570,6 @@ declare module INSPECTOR {
 }
 }
 declare module INSPECTOR {
 declare module INSPECTOR {
     interface ISliderPropertyGridComponentProps {
     interface ISliderPropertyGridComponentProps {
-        globalState: GlobalState;
         slider: BABYLON.GUI.Slider;
         slider: BABYLON.GUI.Slider;
         lockObject: LockObject;
         lockObject: LockObject;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
@@ -1903,36 +1910,6 @@ declare module INSPECTOR {
     }
     }
 }
 }
 declare module INSPECTOR {
 declare module INSPECTOR {
-    export interface IColor4LineComponentProps {
-        label: string;
-        target: any;
-        propertyName: string;
-        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
-        onChange?: () => void;
-        isLinear?: boolean;
-    }
-    export class Color4LineComponent extends React.Component<IColor4LineComponentProps, {
-        isExpanded: boolean;
-        color: BABYLON.Color4;
-    }> {
-        private _localChange;
-        constructor(props: IColor4LineComponentProps);
-        shouldComponentUpdate(nextProps: IColor4LineComponentProps, nextState: {
-            color: BABYLON.Color4;
-        }): boolean;
-        setPropertyValue(newColor: BABYLON.Color4): void;
-        onChange(newValue: string): void;
-        switchExpandState(): void;
-        raiseOnPropertyChanged(previousValue: BABYLON.Color4): void;
-        updateStateR(value: number): void;
-        updateStateG(value: number): void;
-        updateStateB(value: number): void;
-        updateStateA(value: number): void;
-        copyToClipboard(): void;
-        render(): JSX.Element;
-    }
-}
-declare module INSPECTOR {
     interface IGradientStepComponentProps {
     interface IGradientStepComponentProps {
         globalState: GlobalState;
         globalState: GlobalState;
         step: BABYLON.GradientBlockColorStep;
         step: BABYLON.GradientBlockColorStep;
@@ -1971,6 +1948,36 @@ declare module INSPECTOR {
     }
     }
 }
 }
 declare module INSPECTOR {
 declare module INSPECTOR {
+    export interface IColor4LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        onChange?: () => void;
+        isLinear?: boolean;
+    }
+    export class Color4LineComponent extends React.Component<IColor4LineComponentProps, {
+        isExpanded: boolean;
+        color: BABYLON.Color4;
+    }> {
+        private _localChange;
+        constructor(props: IColor4LineComponentProps);
+        shouldComponentUpdate(nextProps: IColor4LineComponentProps, nextState: {
+            color: BABYLON.Color4;
+        }): boolean;
+        setPropertyValue(newColor: BABYLON.Color4): void;
+        onChange(newValue: string): void;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: BABYLON.Color4): void;
+        updateStateR(value: number): void;
+        updateStateG(value: number): void;
+        updateStateB(value: number): void;
+        updateStateA(value: number): void;
+        copyToClipboard(): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     interface INodeMaterialPropertyGridComponentProps {
     interface INodeMaterialPropertyGridComponentProps {
         globalState: GlobalState;
         globalState: GlobalState;
         material: BABYLON.NodeMaterial;
         material: BABYLON.NodeMaterial;
@@ -4397,4 +4404,20 @@ declare module INSPECTOR {
 }
 }
 declare module INSPECTOR {
 declare module INSPECTOR {
     export const Contrast: IToolData;
     export const Contrast: IToolData;
+}
+declare module INSPECTOR {
+    export interface IButtonLineComponentProps {
+        data: string;
+        tooltip: string;
+    }
+    export class DraggableLineComponent extends React.Component<IButtonLineComponentProps> {
+        constructor(props: IButtonLineComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    export class Popup {
+        static CreatePopup(title: string, windowVariableName: string, width?: number, height?: number): HTMLDivElement | null;
+        private static _CopyStyles;
+    }
 }
 }

Fichier diff supprimé car celui-ci est trop grand
+ 223 - 179
dist/preview release/inspector/babylon.inspector.module.d.ts


+ 7 - 7
dist/preview release/inspector/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-inspector",
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
     "description": "The Babylon.js inspector.",
-    "version": "5.0.0-alpha.5",
+    "version": "5.0.0-alpha.6",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -29,12 +29,12 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "5.0.0-alpha.5",
-        "babylonjs-gui": "5.0.0-alpha.5",
-        "babylonjs-loaders": "5.0.0-alpha.5",
-        "babylonjs-materials": "5.0.0-alpha.5",
-        "babylonjs-serializers": "5.0.0-alpha.5",
-        "babylonjs-gltf2interface": "5.0.0-alpha.5"
+        "babylonjs": "5.0.0-alpha.6",
+        "babylonjs-gui": "5.0.0-alpha.6",
+        "babylonjs-loaders": "5.0.0-alpha.6",
+        "babylonjs-materials": "5.0.0-alpha.6",
+        "babylonjs-serializers": "5.0.0-alpha.6",
+        "babylonjs-gltf2interface": "5.0.0-alpha.6"
     },
     },
     "peerDependencies": {
     "peerDependencies": {
         "@types/react": ">=16.7.3",
         "@types/react": ">=16.7.3",

+ 17 - 18
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -2047,28 +2047,27 @@ var KHR_materials_variants = /** @class */ (function () {
                     var root = _this._loader.rootBabylonMesh;
                     var root = _this._loader.rootBabylonMesh;
                     var metadata = (root.metadata = root.metadata || {});
                     var metadata = (root.metadata = root.metadata || {});
                     var gltf = (metadata.gltf = metadata.gltf || {});
                     var gltf = (metadata.gltf = metadata.gltf || {});
-                    var extensionMetadata = (gltf[NAME] = gltf[NAME] || { lastSelected: null, original: [], variants: {} });
+                    var extensionMetadata_1 = (gltf[NAME] = gltf[NAME] || { lastSelected: null, original: [], variants: {} });
                     // Store the original material.
                     // Store the original material.
-                    extensionMetadata.original.push({ mesh: babylonMesh, material: babylonMesh.material });
-                    // For each mapping, look at the variants and make a new entry for them.
-                    var variants_1 = extensionMetadata.variants;
-                    for (var _i = 0, _a = extension.mappings; _i < _a.length; _i++) {
-                        var mapping = _a[_i];
-                        var _loop_1 = function (variantIndex) {
-                            var variant = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(extensionContext + "/mapping/" + variantIndex, _this._variants, variantIndex);
-                            var material = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get("#/materials/", _this._loader.gltf.materials, mapping.material);
-                            promises.push(_this._loader._loadMaterialAsync("#/materials/" + mapping.material, material, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                                variants_1[variant.name] = variants_1[variant.name] || [];
-                                variants_1[variant.name].push({
+                    extensionMetadata_1.original.push({ mesh: babylonMesh, material: babylonMesh.material });
+                    var _loop_1 = function (mappingIndex) {
+                        var mapping = extension.mappings[mappingIndex];
+                        var material = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(extensionContext + "/mappings/" + mappingIndex + "/material", _this._loader.gltf.materials, mapping.material);
+                        promises.push(_this._loader._loadMaterialAsync("#/materials/" + mapping.material, material, babylonMesh, babylonDrawMode, function (babylonMaterial) {
+                            for (var mappingVariantIndex = 0; mappingVariantIndex < mapping.variants.length; ++mappingVariantIndex) {
+                                var variantIndex = mapping.variants[mappingVariantIndex];
+                                var variant = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get("/extensions/" + NAME + "/variants/" + variantIndex, _this._variants, variantIndex);
+                                extensionMetadata_1.variants[variant.name] = extensionMetadata_1.variants[variant.name] || [];
+                                extensionMetadata_1.variants[variant.name].push({
                                     mesh: babylonMesh,
                                     mesh: babylonMesh,
                                     material: babylonMaterial
                                     material: babylonMaterial
                                 });
                                 });
-                            }));
-                        };
-                        for (var _b = 0, _c = mapping.variants; _b < _c.length; _b++) {
-                            var variantIndex = _c[_b];
-                            _loop_1(variantIndex);
-                        }
+                            }
+                        }));
+                    };
+                    // For each mapping, look at the variants and make a new entry for them.
+                    for (var mappingIndex = 0; mappingIndex < extension.mappings.length; ++mappingIndex) {
+                        _loop_1(mappingIndex);
                     }
                     }
                 }
                 }
             }));
             }));

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 17 - 18
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -4399,28 +4399,27 @@ var KHR_materials_variants = /** @class */ (function () {
                     var root = _this._loader.rootBabylonMesh;
                     var root = _this._loader.rootBabylonMesh;
                     var metadata = (root.metadata = root.metadata || {});
                     var metadata = (root.metadata = root.metadata || {});
                     var gltf = (metadata.gltf = metadata.gltf || {});
                     var gltf = (metadata.gltf = metadata.gltf || {});
-                    var extensionMetadata = (gltf[NAME] = gltf[NAME] || { lastSelected: null, original: [], variants: {} });
+                    var extensionMetadata_1 = (gltf[NAME] = gltf[NAME] || { lastSelected: null, original: [], variants: {} });
                     // Store the original material.
                     // Store the original material.
-                    extensionMetadata.original.push({ mesh: babylonMesh, material: babylonMesh.material });
-                    // For each mapping, look at the variants and make a new entry for them.
-                    var variants_1 = extensionMetadata.variants;
-                    for (var _i = 0, _a = extension.mappings; _i < _a.length; _i++) {
-                        var mapping = _a[_i];
-                        var _loop_1 = function (variantIndex) {
-                            var variant = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(extensionContext + "/mapping/" + variantIndex, _this._variants, variantIndex);
-                            var material = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get("#/materials/", _this._loader.gltf.materials, mapping.material);
-                            promises.push(_this._loader._loadMaterialAsync("#/materials/" + mapping.material, material, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                                variants_1[variant.name] = variants_1[variant.name] || [];
-                                variants_1[variant.name].push({
+                    extensionMetadata_1.original.push({ mesh: babylonMesh, material: babylonMesh.material });
+                    var _loop_1 = function (mappingIndex) {
+                        var mapping = extension.mappings[mappingIndex];
+                        var material = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(extensionContext + "/mappings/" + mappingIndex + "/material", _this._loader.gltf.materials, mapping.material);
+                        promises.push(_this._loader._loadMaterialAsync("#/materials/" + mapping.material, material, babylonMesh, babylonDrawMode, function (babylonMaterial) {
+                            for (var mappingVariantIndex = 0; mappingVariantIndex < mapping.variants.length; ++mappingVariantIndex) {
+                                var variantIndex = mapping.variants[mappingVariantIndex];
+                                var variant = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get("/extensions/" + NAME + "/variants/" + variantIndex, _this._variants, variantIndex);
+                                extensionMetadata_1.variants[variant.name] = extensionMetadata_1.variants[variant.name] || [];
+                                extensionMetadata_1.variants[variant.name].push({
                                     mesh: babylonMesh,
                                     mesh: babylonMesh,
                                     material: babylonMaterial
                                     material: babylonMaterial
                                 });
                                 });
-                            }));
-                        };
-                        for (var _b = 0, _c = mapping.variants; _b < _c.length; _b++) {
-                            var variantIndex = _c[_b];
-                            _loop_1(variantIndex);
-                        }
+                            }
+                        }));
+                    };
+                    // For each mapping, look at the variants and make a new entry for them.
+                    for (var mappingIndex = 0; mappingIndex < extension.mappings.length; ++mappingIndex) {
+                        _loop_1(mappingIndex);
                     }
                     }
                 }
                 }
             }));
             }));

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 17 - 18
dist/preview release/loaders/babylonjs.loaders.js

@@ -5835,28 +5835,27 @@ var KHR_materials_variants = /** @class */ (function () {
                     var root = _this._loader.rootBabylonMesh;
                     var root = _this._loader.rootBabylonMesh;
                     var metadata = (root.metadata = root.metadata || {});
                     var metadata = (root.metadata = root.metadata || {});
                     var gltf = (metadata.gltf = metadata.gltf || {});
                     var gltf = (metadata.gltf = metadata.gltf || {});
-                    var extensionMetadata = (gltf[NAME] = gltf[NAME] || { lastSelected: null, original: [], variants: {} });
+                    var extensionMetadata_1 = (gltf[NAME] = gltf[NAME] || { lastSelected: null, original: [], variants: {} });
                     // Store the original material.
                     // Store the original material.
-                    extensionMetadata.original.push({ mesh: babylonMesh, material: babylonMesh.material });
-                    // For each mapping, look at the variants and make a new entry for them.
-                    var variants_1 = extensionMetadata.variants;
-                    for (var _i = 0, _a = extension.mappings; _i < _a.length; _i++) {
-                        var mapping = _a[_i];
-                        var _loop_1 = function (variantIndex) {
-                            var variant = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(extensionContext + "/mapping/" + variantIndex, _this._variants, variantIndex);
-                            var material = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get("#/materials/", _this._loader.gltf.materials, mapping.material);
-                            promises.push(_this._loader._loadMaterialAsync("#/materials/" + mapping.material, material, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                                variants_1[variant.name] = variants_1[variant.name] || [];
-                                variants_1[variant.name].push({
+                    extensionMetadata_1.original.push({ mesh: babylonMesh, material: babylonMesh.material });
+                    var _loop_1 = function (mappingIndex) {
+                        var mapping = extension.mappings[mappingIndex];
+                        var material = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(extensionContext + "/mappings/" + mappingIndex + "/material", _this._loader.gltf.materials, mapping.material);
+                        promises.push(_this._loader._loadMaterialAsync("#/materials/" + mapping.material, material, babylonMesh, babylonDrawMode, function (babylonMaterial) {
+                            for (var mappingVariantIndex = 0; mappingVariantIndex < mapping.variants.length; ++mappingVariantIndex) {
+                                var variantIndex = mapping.variants[mappingVariantIndex];
+                                var variant = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get("/extensions/" + NAME + "/variants/" + variantIndex, _this._variants, variantIndex);
+                                extensionMetadata_1.variants[variant.name] = extensionMetadata_1.variants[variant.name] || [];
+                                extensionMetadata_1.variants[variant.name].push({
                                     mesh: babylonMesh,
                                     mesh: babylonMesh,
                                     material: babylonMaterial
                                     material: babylonMaterial
                                 });
                                 });
-                            }));
-                        };
-                        for (var _b = 0, _c = mapping.variants; _b < _c.length; _b++) {
-                            var variantIndex = _c[_b];
-                            _loop_1(variantIndex);
-                        }
+                            }
+                        }));
+                    };
+                    // For each mapping, look at the variants and make a new entry for them.
+                    for (var mappingIndex = 0; mappingIndex < extension.mappings.length; ++mappingIndex) {
+                        _loop_1(mappingIndex);
                     }
                     }
                 }
                 }
             }));
             }));

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


+ 3 - 3
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-loaders",
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "5.0.0-alpha.5",
+    "version": "5.0.0-alpha.6",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs-gltf2interface": "5.0.0-alpha.5",
-        "babylonjs": "5.0.0-alpha.5"
+        "babylonjs-gltf2interface": "5.0.0-alpha.6",
+        "babylonjs": "5.0.0-alpha.6"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

+ 2 - 2
dist/preview release/materialsLibrary/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-materials",
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "5.0.0-alpha.5",
+    "version": "5.0.0-alpha.6",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "5.0.0-alpha.5"
+        "babylonjs": "5.0.0-alpha.6"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

+ 448 - 14
dist/preview release/nodeEditor/babylon.nodeEditor.d.ts

@@ -1681,6 +1681,15 @@ declare module NODEEDITOR {
     }
     }
 }
 }
 declare module NODEEDITOR {
 declare module NODEEDITOR {
+    export class PropertyChangedEvent {
+        object: any;
+        property: string;
+        value: any;
+        initialValue: any;
+        allowNullValue?: boolean;
+    }
+}
+declare module NODEEDITOR {
     export interface IBooleanLineComponentProps {
     export interface IBooleanLineComponentProps {
         label: string;
         label: string;
         value: boolean;
         value: boolean;
@@ -1701,6 +1710,146 @@ declare module NODEEDITOR {
     }
     }
 }
 }
 declare module NODEEDITOR {
 declare module NODEEDITOR {
+    export interface ICheckBoxLineComponentProps {
+        label: string;
+        target?: any;
+        propertyName?: string;
+        isSelected?: () => boolean;
+        onSelect?: (value: boolean) => void;
+        onValueChanged?: () => void;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        disabled?: boolean;
+    }
+    export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponentProps, {
+        isSelected: boolean;
+        isDisabled?: boolean;
+    }> {
+        private static _UniqueIdSeed;
+        private _uniqueId;
+        private _localChange;
+        constructor(props: ICheckBoxLineComponentProps);
+        shouldComponentUpdate(nextProps: ICheckBoxLineComponentProps, nextState: {
+            isSelected: boolean;
+            isDisabled: boolean;
+        }): boolean;
+        onChange(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface INumericInputComponentProps {
+        label: string;
+        value: number;
+        step?: number;
+        onChange: (value: number) => void;
+        precision?: number;
+    }
+    export class NumericInputComponent extends React.Component<INumericInputComponentProps, {
+        value: string;
+    }> {
+        static defaultProps: {
+            step: number;
+        };
+        private _localChange;
+        constructor(props: INumericInputComponentProps);
+        shouldComponentUpdate(nextProps: INumericInputComponentProps, nextState: {
+            value: string;
+        }): boolean;
+        updateValue(evt: any): void;
+        onBlur(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    export interface IColorPickerComponentProps {
+        value: BABYLON.Color4 | BABYLON.Color3;
+        onColorChanged: (newOne: string) => void;
+    }
+    interface IColorPickerComponentState {
+        pickerEnabled: boolean;
+        color: BABYLON.Color3 | BABYLON.Color4;
+        hex: string;
+    }
+    export class ColorPickerLineComponent extends React.Component<IColorPickerComponentProps, IColorPickerComponentState> {
+        private _floatRef;
+        private _floatHostRef;
+        constructor(props: IColorPickerComponentProps);
+        syncPositions(): void;
+        shouldComponentUpdate(nextProps: IColorPickerComponentProps, nextState: IColorPickerComponentState): boolean;
+        componentDidUpdate(): void;
+        componentDidMount(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    export interface IColor3LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        isLinear?: boolean;
+    }
+    export class Color3LineComponent extends React.Component<IColor3LineComponentProps, {
+        isExpanded: boolean;
+        color: BABYLON.Color3;
+    }> {
+        private _localChange;
+        constructor(props: IColor3LineComponentProps);
+        shouldComponentUpdate(nextProps: IColor3LineComponentProps, nextState: {
+            color: BABYLON.Color3;
+        }): boolean;
+        setPropertyValue(newColor: BABYLON.Color3): void;
+        onChange(newValue: string): void;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: BABYLON.Color3): void;
+        updateStateR(value: number): void;
+        updateStateG(value: number): void;
+        updateStateB(value: number): void;
+        copyToClipboard(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    export interface IColor4LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        onChange?: () => void;
+        isLinear?: boolean;
+    }
+    export class Color4LineComponent extends React.Component<IColor4LineComponentProps, {
+        isExpanded: boolean;
+        color: BABYLON.Color4;
+    }> {
+        private _localChange;
+        constructor(props: IColor4LineComponentProps);
+        shouldComponentUpdate(nextProps: IColor4LineComponentProps, nextState: {
+            color: BABYLON.Color4;
+        }): boolean;
+        setPropertyValue(newColor: BABYLON.Color4): void;
+        onChange(newValue: string): void;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: BABYLON.Color4): void;
+        updateStateR(value: number): void;
+        updateStateG(value: number): void;
+        updateStateB(value: number): void;
+        updateStateA(value: number): void;
+        copyToClipboard(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    export interface IButtonLineComponentProps {
+        data: string;
+        tooltip: string;
+    }
+    export class DraggableLineComponent extends React.Component<IButtonLineComponentProps> {
+        constructor(props: IButtonLineComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
     interface IFileButtonLineComponentProps {
     interface IFileButtonLineComponentProps {
         label: string;
         label: string;
         onClick: (file: File) => void;
         onClick: (file: File) => void;
@@ -1731,6 +1880,117 @@ declare module NODEEDITOR {
     }
     }
 }
 }
 declare module NODEEDITOR {
 declare module NODEEDITOR {
+    /**
+     * Class used to provide lock mechanism
+     */
+    export class LockObject {
+        /**
+         * Gets or set if the lock is engaged
+         */
+        lock: boolean;
+    }
+}
+declare module NODEEDITOR {
+    interface ISliderLineComponentProps {
+        label: string;
+        target?: any;
+        propertyName?: string;
+        minimum: number;
+        maximum: number;
+        step: number;
+        directValue?: number;
+        useEuler?: boolean;
+        onChange?: (value: number) => void;
+        onInput?: (value: number) => void;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        decimalCount?: number;
+        margin?: boolean;
+    }
+    export class SliderLineComponent extends React.Component<ISliderLineComponentProps, {
+        value: number;
+    }> {
+        private _localChange;
+        constructor(props: ISliderLineComponentProps);
+        shouldComponentUpdate(nextProps: ISliderLineComponentProps, nextState: {
+            value: number;
+        }): boolean;
+        onChange(newValueString: any): void;
+        onInput(newValueString: any): void;
+        prepareDataToRead(value: number): number;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface IFloatLineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        lockObject?: LockObject;
+        onChange?: (newValue: number) => void;
+        isInteger?: boolean;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        additionalClass?: string;
+        step?: string;
+        digits?: number;
+        useEuler?: boolean;
+        min?: number;
+        max?: number;
+        smallUI?: boolean;
+        onEnter?: (newValue: number) => void;
+    }
+    export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
+        value: string;
+    }> {
+        private _localChange;
+        private _store;
+        constructor(props: IFloatLineComponentProps);
+        componentWillUnmount(): void;
+        shouldComponentUpdate(nextProps: IFloatLineComponentProps, nextState: {
+            value: string;
+        }): boolean;
+        raiseOnPropertyChanged(newValue: number, previousValue: number): void;
+        updateValue(valueString: string): void;
+        lock(): void;
+        unlock(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface IHexLineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        lockObject?: LockObject;
+        onChange?: (newValue: number) => void;
+        isInteger?: boolean;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        additionalClass?: string;
+        step?: string;
+        digits?: number;
+        useEuler?: boolean;
+        min?: number;
+    }
+    export class HexLineComponent extends React.Component<IHexLineComponentProps, {
+        value: string;
+    }> {
+        private _localChange;
+        private _store;
+        private _propertyChange;
+        constructor(props: IHexLineComponentProps);
+        componentWillUnmount(): void;
+        shouldComponentUpdate(nextProps: IHexLineComponentProps, nextState: {
+            value: string;
+        }): boolean;
+        raiseOnPropertyChanged(newValue: number, previousValue: number): void;
+        convertToHexString(valueString: string): string;
+        updateValue(valueString: string, raisePropertyChanged: boolean): void;
+        lock(): void;
+        unlock(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
     export interface IIconButtonLineComponentProps {
     export interface IIconButtonLineComponentProps {
         icon: string;
         icon: string;
         onClick: () => void;
         onClick: () => void;
@@ -1759,6 +2019,21 @@ declare module NODEEDITOR {
     }
     }
 }
 }
 declare module NODEEDITOR {
 declare module NODEEDITOR {
+    interface ILineContainerComponentProps {
+        title: string;
+        children: any[] | any;
+        closed?: boolean;
+    }
+    export class LineContainerComponent extends React.Component<ILineContainerComponentProps, {
+        isExpanded: boolean;
+    }> {
+        constructor(props: ILineContainerComponentProps);
+        switchExpandedState(): void;
+        renderHeader(): JSX.Element;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
     interface ILinkButtonComponentProps {
     interface ILinkButtonComponentProps {
         label: string;
         label: string;
         buttonLabel: string;
         buttonLabel: string;
@@ -1783,30 +2058,45 @@ declare module NODEEDITOR {
     }
     }
 }
 }
 declare module NODEEDITOR {
 declare module NODEEDITOR {
-    interface INumericInputComponentProps {
+    export const Null_Value: number;
+    export class ListLineOption {
         label: string;
         label: string;
         value: number;
         value: number;
-        step?: number;
-        onChange: (value: number) => void;
-        precision?: number;
+        selected?: boolean;
     }
     }
-    export class NumericInputComponent extends React.Component<INumericInputComponentProps, {
-        value: string;
+    export interface IOptionsLineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        options: ListLineOption[];
+        noDirectUpdate?: boolean;
+        onSelect?: (value: number) => void;
+        extractValue?: () => number;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        allowNullValue?: boolean;
+    }
+    export class OptionsLineComponent extends React.Component<IOptionsLineComponentProps, {
+        value: number;
     }> {
     }> {
-        static defaultProps: {
-            step: number;
-        };
         private _localChange;
         private _localChange;
-        constructor(props: INumericInputComponentProps);
-        shouldComponentUpdate(nextProps: INumericInputComponentProps, nextState: {
-            value: string;
+        private remapValueIn;
+        private remapValueOut;
+        constructor(props: IOptionsLineComponentProps);
+        shouldComponentUpdate(nextProps: IOptionsLineComponentProps, nextState: {
+            value: number;
         }): boolean;
         }): boolean;
-        updateValue(evt: any): void;
-        onBlur(): void;
+        raiseOnPropertyChanged(newValue: number, previousValue: number): void;
+        updateValue(valueString: string): void;
         render(): JSX.Element;
         render(): JSX.Element;
     }
     }
 }
 }
 declare module NODEEDITOR {
 declare module NODEEDITOR {
+    export class Popup {
+        static CreatePopup(title: string, windowVariableName: string, width?: number, height?: number): HTMLDivElement | null;
+        private static _CopyStyles;
+    }
+}
+declare module NODEEDITOR {
     interface IRadioButtonLineComponentProps {
     interface IRadioButtonLineComponentProps {
         onSelectionChangedObservable: BABYLON.Observable<RadioButtonLineComponent>;
         onSelectionChangedObservable: BABYLON.Observable<RadioButtonLineComponent>;
         label: string;
         label: string;
@@ -1825,6 +2115,30 @@ declare module NODEEDITOR {
     }
     }
 }
 }
 declare module NODEEDITOR {
 declare module NODEEDITOR {
+    interface ITextInputLineComponentProps {
+        label: string;
+        lockObject: LockObject;
+        target?: any;
+        propertyName?: string;
+        value?: string;
+        onChange?: (value: string) => void;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class TextInputLineComponent extends React.Component<ITextInputLineComponentProps, {
+        value: string;
+    }> {
+        private _localChange;
+        constructor(props: ITextInputLineComponentProps);
+        componentWillUnmount(): void;
+        shouldComponentUpdate(nextProps: ITextInputLineComponentProps, nextState: {
+            value: string;
+        }): boolean;
+        raiseOnPropertyChanged(newValue: string, previousValue: string): void;
+        updateValue(value: string): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
     interface ITextLineComponentProps {
     interface ITextLineComponentProps {
         label?: string;
         label?: string;
         value?: string;
         value?: string;
@@ -1854,4 +2168,124 @@ declare module NODEEDITOR {
         constructor(props: IValueLineComponentProps);
         constructor(props: IValueLineComponentProps);
         render(): JSX.Element;
         render(): JSX.Element;
     }
     }
+}
+declare module NODEEDITOR {
+    interface IVector2LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        step?: number;
+        onChange?: (newvalue: BABYLON.Vector2) => void;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class Vector2LineComponent extends React.Component<IVector2LineComponentProps, {
+        isExpanded: boolean;
+        value: BABYLON.Vector2;
+    }> {
+        static defaultProps: {
+            step: number;
+        };
+        private _localChange;
+        constructor(props: IVector2LineComponentProps);
+        shouldComponentUpdate(nextProps: IVector2LineComponentProps, nextState: {
+            isExpanded: boolean;
+            value: BABYLON.Vector2;
+        }): boolean;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: BABYLON.Vector2): void;
+        updateStateX(value: number): void;
+        updateStateY(value: number): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface IVector3LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        step?: number;
+        onChange?: (newvalue: BABYLON.Vector3) => void;
+        useEuler?: boolean;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        noSlider?: boolean;
+    }
+    export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
+        isExpanded: boolean;
+        value: BABYLON.Vector3;
+    }> {
+        static defaultProps: {
+            step: number;
+        };
+        private _localChange;
+        constructor(props: IVector3LineComponentProps);
+        getCurrentValue(): any;
+        shouldComponentUpdate(nextProps: IVector3LineComponentProps, nextState: {
+            isExpanded: boolean;
+            value: BABYLON.Vector3;
+        }): boolean;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: BABYLON.Vector3): void;
+        updateVector3(): void;
+        updateStateX(value: number): void;
+        updateStateY(value: number): void;
+        updateStateZ(value: number): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface IVector4LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        step?: number;
+        onChange?: (newvalue: BABYLON.Vector4) => void;
+        useEuler?: boolean;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class Vector4LineComponent extends React.Component<IVector4LineComponentProps, {
+        isExpanded: boolean;
+        value: BABYLON.Vector4;
+    }> {
+        static defaultProps: {
+            step: number;
+        };
+        private _localChange;
+        constructor(props: IVector4LineComponentProps);
+        getCurrentValue(): any;
+        shouldComponentUpdate(nextProps: IVector4LineComponentProps, nextState: {
+            isExpanded: boolean;
+            value: BABYLON.Vector4;
+        }): boolean;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: BABYLON.Vector4): void;
+        updateVector4(): void;
+        updateStateX(value: number): void;
+        updateStateY(value: number): void;
+        updateStateZ(value: number): void;
+        updateStateW(value: number): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface ICommonControlPropertyGridComponentProps {
+        control: Control;
+        lockObject: LockObject;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class CommonControlPropertyGridComponent extends React.Component<ICommonControlPropertyGridComponentProps> {
+        constructor(props: ICommonControlPropertyGridComponentProps);
+        renderGridInformation(): JSX.Element | null;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface ISliderPropertyGridComponentProps {
+        slider: Slider;
+        lockObject: LockObject;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class SliderPropertyGridComponent extends React.Component<ISliderPropertyGridComponentProps> {
+        constructor(props: ISliderPropertyGridComponentProps);
+        render(): JSX.Element;
+    }
 }
 }

+ 6 - 6
dist/preview release/nodeEditor/babylon.nodeEditor.max.js

@@ -62793,7 +62793,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _diagram_graphFrame__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./diagram/graphFrame */ "./diagram/graphFrame.ts");
 /* harmony import */ var _diagram_graphFrame__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./diagram/graphFrame */ "./diagram/graphFrame.ts");
 /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! react-dom */ "../../node_modules/react-dom/index.js");
 /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! react-dom */ "../../node_modules/react-dom/index.js");
 /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_15___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_15__);
 /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_15___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_15__);
-/* harmony import */ var _sharedComponents_popup__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./sharedComponents/popup */ "./sharedComponents/popup.ts");
+/* harmony import */ var _sharedComponents_popup__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./sharedComponents/popup */ "./sharedComponents/popup.tsx");
 
 
 
 
 
 
@@ -63576,7 +63576,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _globalState__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./globalState */ "./globalState.ts");
 /* harmony import */ var _globalState__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./globalState */ "./globalState.ts");
 /* harmony import */ var _graphEditor__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./graphEditor */ "./graphEditor.tsx");
 /* harmony import */ var _graphEditor__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./graphEditor */ "./graphEditor.tsx");
-/* harmony import */ var _src_sharedComponents_popup__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../src/sharedComponents/popup */ "./sharedComponents/popup.ts");
+/* harmony import */ var _src_sharedComponents_popup__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../src/sharedComponents/popup */ "./sharedComponents/popup.tsx");
 /* harmony import */ var _serializationTools__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./serializationTools */ "./serializationTools.ts");
 /* harmony import */ var _serializationTools__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./serializationTools */ "./serializationTools.ts");
 /* harmony import */ var _components_preview_previewType__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./components/preview/previewType */ "./components/preview/previewType.ts");
 /* harmony import */ var _components_preview_previewType__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./components/preview/previewType */ "./components/preview/previewType.ts");
 /* harmony import */ var babylonjs_Misc_dataStorage__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/dataStorage */ "babylonjs/Misc/dataStorage");
 /* harmony import */ var babylonjs_Misc_dataStorage__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/dataStorage */ "babylonjs/Misc/dataStorage");
@@ -64971,10 +64971,10 @@ module.exports = "data:image/svg+xml,%3Csvg viewBox='0 0 24 24' version='1.1' xm
 
 
 /***/ }),
 /***/ }),
 
 
-/***/ "./sharedComponents/popup.ts":
-/*!***********************************!*\
-  !*** ./sharedComponents/popup.ts ***!
-  \***********************************/
+/***/ "./sharedComponents/popup.tsx":
+/*!************************************!*\
+  !*** ./sharedComponents/popup.tsx ***!
+  \************************************/
 /*! exports provided: Popup */
 /*! exports provided: Popup */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1002 - 79
dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts


+ 2 - 2
dist/preview release/nodeEditor/package.json

@@ -4,14 +4,14 @@
     },
     },
     "name": "babylonjs-node-editor",
     "name": "babylonjs-node-editor",
     "description": "The Babylon.js node material editor.",
     "description": "The Babylon.js node material editor.",
-    "version": "5.0.0-alpha.5",
+    "version": "5.0.0-alpha.6",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
     },
     },
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "5.0.0-alpha.5"
+        "babylonjs": "5.0.0-alpha.6"
     },
     },
     "files": [
     "files": [
         "babylon.nodeEditor.max.js.map",
         "babylon.nodeEditor.max.js.map",

+ 1 - 1
dist/preview release/package.json

@@ -7,7 +7,7 @@
     ],
     ],
     "name": "babylonjs",
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "5.0.0-alpha.5",
+    "version": "5.0.0-alpha.6",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/packagesSizeBaseLine.json

@@ -1 +1 @@
-{"thinEngineOnly":130009,"engineOnly":167383,"sceneOnly":522497,"minGridMaterial":698122,"minStandardMaterial":860714}
+{"thinEngineOnly":130230,"engineOnly":167557,"sceneOnly":523120,"minGridMaterial":699118,"minStandardMaterial":862977}

+ 2 - 2
dist/preview release/postProcessesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-post-process",
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "5.0.0-alpha.5",
+    "version": "5.0.0-alpha.6",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "5.0.0-alpha.5"
+        "babylonjs": "5.0.0-alpha.6"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

+ 2 - 2
dist/preview release/proceduralTexturesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-procedural-textures",
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "5.0.0-alpha.5",
+    "version": "5.0.0-alpha.6",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "5.0.0-alpha.5"
+        "babylonjs": "5.0.0-alpha.6"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

+ 0 - 1
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -4724,7 +4724,6 @@ var _GLTFMaterialExporter = /** @class */ (function () {
         return this._finishMaterial(promises, glTFMaterial, babylonPBRMaterial, mimeType);
         return this._finishMaterial(promises, glTFMaterial, babylonPBRMaterial, mimeType);
     };
     };
     _GLTFMaterialExporter.prototype.getPixelsFromTexture = function (babylonTexture) {
     _GLTFMaterialExporter.prototype.getPixelsFromTexture = function (babylonTexture) {
-        // TODO WEBGPU remove the as unknown cast once using the new babylonjs package to compile the glTF material exporter
         var pixels = babylonTexture.textureType === babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Constants"].TEXTURETYPE_UNSIGNED_INT ? babylonTexture.readPixels() : babylonTexture.readPixels();
         var pixels = babylonTexture.textureType === babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Constants"].TEXTURETYPE_UNSIGNED_INT ? babylonTexture.readPixels() : babylonTexture.readPixels();
         return pixels;
         return pixels;
     };
     };

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.js.map


+ 0 - 1
dist/preview release/serializers/babylonjs.serializers.js

@@ -4909,7 +4909,6 @@ var _GLTFMaterialExporter = /** @class */ (function () {
         return this._finishMaterial(promises, glTFMaterial, babylonPBRMaterial, mimeType);
         return this._finishMaterial(promises, glTFMaterial, babylonPBRMaterial, mimeType);
     };
     };
     _GLTFMaterialExporter.prototype.getPixelsFromTexture = function (babylonTexture) {
     _GLTFMaterialExporter.prototype.getPixelsFromTexture = function (babylonTexture) {
-        // TODO WEBGPU remove the as unknown cast once using the new babylonjs package to compile the glTF material exporter
         var pixels = babylonTexture.textureType === babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Constants"].TEXTURETYPE_UNSIGNED_INT ? babylonTexture.readPixels() : babylonTexture.readPixels();
         var pixels = babylonTexture.textureType === babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["Constants"].TEXTURETYPE_UNSIGNED_INT ? babylonTexture.readPixels() : babylonTexture.readPixels();
         return pixels;
         return pixels;
     };
     };

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.js.map


+ 3 - 3
dist/preview release/serializers/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-serializers",
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "5.0.0-alpha.5",
+    "version": "5.0.0-alpha.6",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "5.0.0-alpha.5",
-        "babylonjs-gltf2interface": "5.0.0-alpha.5"
+        "babylonjs": "5.0.0-alpha.6",
+        "babylonjs-gltf2interface": "5.0.0-alpha.6"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

Fichier diff supprimé car celui-ci est trop grand
+ 907 - 485
dist/preview release/viewer/babylon.module.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 83 - 63
dist/preview release/viewer/babylon.viewer.js


Fichier diff supprimé car celui-ci est trop grand
+ 3 - 3
dist/preview release/viewer/babylon.viewer.max.js


+ 23 - 4
dist/preview release/what's new.md

@@ -2,6 +2,8 @@
 
 
 ## Major updates
 ## Major updates
 
 
+- Infinite Morph Targets: When supported (WebGL2+) you are no more limited to 4 morph targets per mesh ([Deltakosh](https://github.com/deltakosh))
+
 ## Updates
 ## Updates
 
 
 ### General
 ### General
@@ -12,10 +14,12 @@
 - Added support for infinite perspective cameras ([Deltakosh](https://github.com/deltakosh))
 - Added support for infinite perspective cameras ([Deltakosh](https://github.com/deltakosh))
 - Added ability to enable/disable ArcRotateCamera zoom on multiTouch event ([NicolasBuecher](https://github.com/NicolasBuecher))
 - Added ability to enable/disable ArcRotateCamera zoom on multiTouch event ([NicolasBuecher](https://github.com/NicolasBuecher))
 - Moving button to shared uI folder.([msDestiny14](https://github.com/msDestiny14))
 - Moving button to shared uI folder.([msDestiny14](https://github.com/msDestiny14))
-- Moving additional components to shared UI folder.([msDestiny14](https://github.com/msDestiny14))
+- Moved sharedUI component to shared UI folder. ([msDestiny14](https://github.com/msDestiny14))
 - Added encapsulate and encapsulateBoundingInfo methods to BoundingInfo. ([Tolo789](https://github.com/Tolo789))
 - Added encapsulate and encapsulateBoundingInfo methods to BoundingInfo. ([Tolo789](https://github.com/Tolo789))
+- Added onLoadObservable to the textureDome class(es) ([RaananW](https://github.com/RaananW))
 
 
 ### Engine
 ### Engine
+
 - Moved all instance data from Geometry to Mesh such that the same Geometry objects can be used by many meshes with instancing. Reduces memory consumption on CPU/GPU. ([breakin](https://github.com/breakin)
 - Moved all instance data from Geometry to Mesh such that the same Geometry objects can be used by many meshes with instancing. Reduces memory consumption on CPU/GPU. ([breakin](https://github.com/breakin)
 
 
 ### Loaders
 ### Loaders
@@ -48,12 +52,18 @@
 - Increased float precision to 4([msDestiny14](https://github.com/msDestiny14))
 - Increased float precision to 4([msDestiny14](https://github.com/msDestiny14))
 - Added ability to make input node's properties visible in the properties of a custom frame ([msDestiny14](https://github.com/msDestiny14))
 - Added ability to make input node's properties visible in the properties of a custom frame ([msDestiny14](https://github.com/msDestiny14))
 
 
+### GUIEditor
+
+- Added GUI Editor project to master. ([msDestiny14](https://github.com/msDestiny14))
+- Moving GUI property tab components into GUIEditor: Slider. ([msDestiny14](https://github.com/msDestiny14))
+
 ### GUI
 ### GUI
 
 
 - Added a `FocusableButton` gui control to simplify creating menus with keyboard navigation ([Flux159](https://github.com/Flux159))
 - Added a `FocusableButton` gui control to simplify creating menus with keyboard navigation ([Flux159](https://github.com/Flux159))
 - Added `focus()` and `blur()` functions for controls that implement `IFocusableControl` ([Flux159](https://github.com/Flux159))
 - Added `focus()` and `blur()` functions for controls that implement `IFocusableControl` ([Flux159](https://github.com/Flux159))
 - Added `ToggleButton` GUI control ([kintz09](https://github.com/kintz09))
 - Added `ToggleButton` GUI control ([kintz09](https://github.com/kintz09))
 - Added shorthand methods which set all padding values at once, named `setPadding` and `setPaddingInPixels`, to the control class  ([kintz09](https://github.com/kintz09))
 - Added shorthand methods which set all padding values at once, named `setPadding` and `setPaddingInPixels`, to the control class  ([kintz09](https://github.com/kintz09))
+- Added two touch-enabled GUI controls, `TouchMeshButton3D` and `TouchHolographicButton`, added option on the WebXR hand tracking feature for enabling touch collisions ([rickfromwork](https://github.com/rickfromwork), [satyapoojasama](https://github.com/satyapoojasama))
 
 
 ### WebXR
 ### WebXR
 
 
@@ -61,6 +71,13 @@
 - Added a way to extend the XRSessionInit Object from inside of a feature ([RaananW](https://github.com/RaananW))
 - Added a way to extend the XRSessionInit Object from inside of a feature ([RaananW](https://github.com/RaananW))
 - Added image tracking feature ([RaananW](https://github.com/RaananW))
 - Added image tracking feature ([RaananW](https://github.com/RaananW))
 - Pointer Events of WebXR controllers have pointerType `xr` ([RaananW](https://github.com/RaananW))
 - Pointer Events of WebXR controllers have pointerType `xr` ([RaananW](https://github.com/RaananW))
+- better support for custom hand meshes ([RaananW](https://github.com/RaananW))
+- Allow disabling of the WebXRControllerPointerSelection feature as part of the WebXR Default Experience ([rgerd](https://github.com/rgerd))
+- Added two touch-enabled GUI controls, `TouchMeshButton3D` and `TouchHolographicButton`, added option on the WebXR hand tracking feature for enabling touch collisions ([rickfromwork](https://github.com/rickfromwork), [satyapoojasama](https://github.com/satyapoojasama))
+
+### Viewer
+
+- Fixed an issue with dual callback binding in case of a forced redraw ([#9608](https://github.com/BabylonJS/Babylon.js/issues/9608)) ([RaananW](https://github.com/RaananW))
 
 
 ## Bugs
 ## Bugs
 
 
@@ -70,6 +87,7 @@
 - Fix issue where PBRSpecularGlossiness materials were excluded from export [#9423](https://github.com/BabylonJS/Babylon.js/issues/9423)([Drigax](https://github.com/drigax))
 - Fix issue where PBRSpecularGlossiness materials were excluded from export [#9423](https://github.com/BabylonJS/Babylon.js/issues/9423)([Drigax](https://github.com/drigax))
 - Fix issue when scaling is reapplied with BoundingBoxGizmo and GizmoManager ([CedricGuillemet](https://github.com/CedricGuillemet))
 - Fix issue when scaling is reapplied with BoundingBoxGizmo and GizmoManager ([CedricGuillemet](https://github.com/CedricGuillemet))
 - Fix direct loading of a glTF string that has base64-encoded URI. ([bghgary](https://github.com/bghgary))
 - Fix direct loading of a glTF string that has base64-encoded URI. ([bghgary](https://github.com/bghgary))
+- Fix capsule impostor size computation for ammojs ([CedricGuillemet](https://github.com/CedricGuillemet))
 - Fix crash of some node materials using instances on iOS ([Popov72](https://github.com/Popov72))
 - Fix crash of some node materials using instances on iOS ([Popov72](https://github.com/Popov72))
 - Fix the code generated for the NME gradient block ([Popov72](https://github.com/Popov72))
 - Fix the code generated for the NME gradient block ([Popov72](https://github.com/Popov72))
 - Fix ssao2RenderingPipeline for orthographic cameras ([Kesshi](https://github.com/Kesshi))
 - Fix ssao2RenderingPipeline for orthographic cameras ([Kesshi](https://github.com/Kesshi))
@@ -89,13 +107,14 @@
 - Fix SSAO2 with PrePass sometimes causing colors brighter than they should be ([CraigFeldspar](https://github.com/CraigFeldspar))
 - Fix SSAO2 with PrePass sometimes causing colors brighter than they should be ([CraigFeldspar](https://github.com/CraigFeldspar))
 - Fix PostProcess sharing between cameras/renderTargets, that would create/destroy a texture on every frame ([CraigFeldspar](https://github.com/CraigFeldspar))
 - Fix PostProcess sharing between cameras/renderTargets, that would create/destroy a texture on every frame ([CraigFeldspar](https://github.com/CraigFeldspar))
 - Fix for DualSense gamepads being incorrectly read as DualShock gamepads ([PolygonalSun](https://github.com/PolygonalSun))
 - Fix for DualSense gamepads being incorrectly read as DualShock gamepads ([PolygonalSun](https://github.com/PolygonalSun))
-
+- Fix for warning in chrome about passive wheel events ([#9777](https://github.com/BabylonJS/Babylon.js/pull/9777)) ([kaliatech](https://github.com/kaliatech))
+- Fix crash when cloning material in `AssetContainer.instantiateModelsToScene` when mesh is an instanced mesh ([Popov72](https://github.com/Popov72))
 
 
 ## Breaking changes
 ## Breaking changes
 
 
 - [List of breaking changes introduced by ou compatibility with WebGPU](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges)
 - [List of breaking changes introduced by ou compatibility with WebGPU](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges)
-    - [ReadPixels and ProceduralTexture.getContent are now async](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges#readpixels-is-now-asynchronous)
-    - [Shader support differences](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges#shader-code-differences)
+  - [ReadPixels and ProceduralTexture.getContent are now async](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges#readpixels-is-now-asynchronous)
+  - [Shader support differences](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges#shader-code-differences)
 - Use both `mesh.visibility` and `material.alpha` values to compute the global alpha value used by the soft transparent shadow rendering code. Formerly was only using `mesh.visibility` ([Popov72](https://github.com/Popov72))
 - Use both `mesh.visibility` and `material.alpha` values to compute the global alpha value used by the soft transparent shadow rendering code. Formerly was only using `mesh.visibility` ([Popov72](https://github.com/Popov72))
 - Depth renderer: don't render mesh if `infiniteDistance = true` or if `material.disableDepthWrite = true` ([Popov72](https://github.com/Popov72))
 - Depth renderer: don't render mesh if `infiniteDistance = true` or if `material.disableDepthWrite = true` ([Popov72](https://github.com/Popov72))
 - Mesh.createInstance no longer make a unique Geometry for the Mesh so updating one Geometry can affect more meshes than before. Use Mesh.makeUniqueGeometry for old behaviour. ([breakin](https://github.com/breakin))
 - Mesh.createInstance no longer make a unique Geometry for the Mesh so updating one Geometry can affect more meshes than before. Use Mesh.makeUniqueGeometry for old behaviour. ([breakin](https://github.com/breakin))

+ 20 - 12
gui/src/3D/controls/control3D.ts

@@ -20,7 +20,7 @@ export class Control3D implements IDisposable, IBehaviorAware<Control3D> {
     private _node: Nullable<TransformNode>;
     private _node: Nullable<TransformNode>;
     private _downCount = 0;
     private _downCount = 0;
     private _enterCount = -1;
     private _enterCount = -1;
-    private _downPointerIds: { [id: number]: boolean } = {};
+    private _downPointerIds: { [id: number]: number } = {}; // Store number of pointer downs per ID, from near and far interactions
     private _isVisible = true;
     private _isVisible = true;
 
 
     /** Gets or sets the control position  in world space */
     /** Gets or sets the control position  in world space */
@@ -306,16 +306,16 @@ export class Control3D implements IDisposable, IBehaviorAware<Control3D> {
 
 
     /** @hidden */
     /** @hidden */
     public _onPointerEnter(target: Control3D): boolean {
     public _onPointerEnter(target: Control3D): boolean {
-        if (this._enterCount > 0) {
-            return false;
-        }
-
         if (this._enterCount === -1) { // -1 is for touch input, we are now sure we are with a mouse or pencil
         if (this._enterCount === -1) { // -1 is for touch input, we are now sure we are with a mouse or pencil
             this._enterCount = 0;
             this._enterCount = 0;
         }
         }
 
 
         this._enterCount++;
         this._enterCount++;
 
 
+        if (this._enterCount > 1) {
+            return false;
+        }
+
         this.onPointerEnterObservable.notifyObservers(this, -1, target, this);
         this.onPointerEnterObservable.notifyObservers(this, -1, target, this);
 
 
         if (this.pointerEnterAnimation) {
         if (this.pointerEnterAnimation) {
@@ -327,6 +327,12 @@ export class Control3D implements IDisposable, IBehaviorAware<Control3D> {
 
 
     /** @hidden */
     /** @hidden */
     public _onPointerOut(target: Control3D): void {
     public _onPointerOut(target: Control3D): void {
+        this._enterCount--;
+
+        if (this._enterCount > 0) {
+            return;
+        }
+
         this._enterCount = 0;
         this._enterCount = 0;
 
 
         this.onPointerOutObservable.notifyObservers(this, -1, target, this);
         this.onPointerOutObservable.notifyObservers(this, -1, target, this);
@@ -338,14 +344,12 @@ export class Control3D implements IDisposable, IBehaviorAware<Control3D> {
 
 
     /** @hidden */
     /** @hidden */
     public _onPointerDown(target: Control3D, coordinates: Vector3, pointerId: number, buttonIndex: number): boolean {
     public _onPointerDown(target: Control3D, coordinates: Vector3, pointerId: number, buttonIndex: number): boolean {
-        if (this._downCount !== 0) {
-            this._downCount++;
-            return false;
-        }
-
         this._downCount++;
         this._downCount++;
+        this._downPointerIds[pointerId] = this._downPointerIds[pointerId] + 1 || 1;
 
 
-        this._downPointerIds[pointerId] = true;
+        if (this._downCount !== 1) {
+            return false;
+        }
 
 
         this.onPointerDownObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
         this.onPointerDownObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
 
 
@@ -359,7 +363,11 @@ export class Control3D implements IDisposable, IBehaviorAware<Control3D> {
     /** @hidden */
     /** @hidden */
     public _onPointerUp(target: Control3D, coordinates: Vector3, pointerId: number, buttonIndex: number, notifyClick: boolean): void {
     public _onPointerUp(target: Control3D, coordinates: Vector3, pointerId: number, buttonIndex: number, notifyClick: boolean): void {
         this._downCount--;
         this._downCount--;
-        delete this._downPointerIds[pointerId];
+        this._downPointerIds[pointerId]--;
+
+        if (this._downPointerIds[pointerId] <= 0) {
+            delete this._downPointerIds[pointerId];
+        }
 
 
         if (this._downCount < 0) {
         if (this._downCount < 0) {
             // Handle if forcePointerUp was called prior to this
             // Handle if forcePointerUp was called prior to this

+ 3 - 0
gui/src/3D/controls/index.ts

@@ -9,4 +9,7 @@ export * from "./planePanel";
 export * from "./scatterPanel";
 export * from "./scatterPanel";
 export * from "./spherePanel";
 export * from "./spherePanel";
 export * from "./stackPanel3D";
 export * from "./stackPanel3D";
+export * from "./touchButton3D";
+export * from "./touchMeshButton3D";
+export * from "./touchHolographicButton";
 export * from "./volumeBasedPanel";
 export * from "./volumeBasedPanel";

+ 367 - 0
gui/src/3D/controls/touchButton3D.ts

@@ -0,0 +1,367 @@
+// Assumptions: absolute position of button mesh is inside the mesh
+
+import { DeepImmutableObject } from "babylonjs/types";
+import { Vector3, Quaternion } from "babylonjs/Maths/math.vector";
+import { Mesh } from "babylonjs/Meshes/mesh";
+import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
+import { TransformNode } from "babylonjs/Meshes/transformNode";
+import { Scene } from "babylonjs/scene";
+import { Ray } from "babylonjs/Culling/ray";
+
+import { Button3D } from "./button3D";
+
+/**
+ * Enum for Button States
+ */
+enum ButtonState {
+    /** None */
+    None = 0,
+    /** Pointer Entered */
+    Hover = 1,
+    /** Pointer Down */
+    Press = 2
+}
+
+/**
+ * Class used to create a touchable button in 3D
+ */
+export class TouchButton3D extends Button3D {
+    private _collisionMesh: Mesh;
+    private _collidableFrontDirection: Vector3;
+    private _lastTouchPoint: Vector3;
+    private _tempButtonForwardRay: Ray;
+    private _lastKnownCollidableScale: Vector3;
+
+    private _collidableInitialized = false;
+
+    private _frontOffset = 0;
+    private _backOffset = 0;
+    private _hoverOffset = 0;
+    private _pushThroughBackOffset = 0;
+
+    private _activeInteractions = new Map<number, ButtonState>();
+    private _previousHeight = new Map<number, number>();
+
+    /**
+     * Creates a new touchable button
+     * @param name defines the control name
+     * @param collisionMesh mesh to track collisions with
+     */
+    constructor(name?: string, collisionMesh?: Mesh) {
+        super(name);
+
+        this._tempButtonForwardRay = new Ray(Vector3.Zero(), Vector3.Zero());
+
+        if (collisionMesh) {
+            this.collisionMesh = collisionMesh;
+        }
+    }
+
+    /**
+     * Sets the front-facing direction of the button
+     * @param frontDir the forward direction of the button
+     */
+    public set collidableFrontDirection(frontWorldDir: Vector3) {
+        this._collidableFrontDirection = frontWorldDir.normalize();
+
+        // Zero out the scale to force it to be proplerly updated in _updateDistanceOffsets
+        this._lastKnownCollidableScale = Vector3.Zero();
+
+        this._updateDistanceOffsets();
+    }
+
+    private _getWorldMatrixData(mesh: Mesh) {
+        let translation = Vector3.Zero();
+        let rotation = Quaternion.Identity();
+        let scale = Vector3.Zero();
+
+        mesh.getWorldMatrix().decompose(scale, rotation, translation);
+
+        return {translation: translation, rotation: rotation, scale: scale};
+    }
+
+    /**
+     * Sets the mesh used for testing input collision
+     * @param collisionMesh the new collision mesh for the button
+     */
+    public set collisionMesh(collisionMesh: Mesh) {
+        if (this._collisionMesh) {
+            this._collisionMesh.dispose();
+        }
+
+        // parent the mesh to sync transforms
+        if (!collisionMesh.parent && this.mesh) {
+            collisionMesh.setParent(this.mesh);
+        }
+
+        this._collisionMesh = collisionMesh;
+        this._collisionMesh.metadata = this;
+
+        this.collidableFrontDirection = collisionMesh.forward;
+
+        this._collidableInitialized = true;
+    }
+
+    /*
+     * Given a point, and two points on a line, this returns the distance between
+     * the point and the closest point on the line. The closest point on the line
+     * does not have to be between the two given points.
+     *
+     * Based off the 3D point-line distance equation
+     *
+     * Assumes lineDirection is normalized
+     */
+    private _getShortestDistancePointToLine(point: Vector3, linePoint: Vector3, lineDirection: Vector3) {
+        const pointToLine = linePoint.subtract(point);
+        const cross = lineDirection.cross(pointToLine);
+
+        return cross.length();
+    }
+
+    /*
+     * Checks to see if collidable is in a position to interact with the button
+     *   - check if collidable has a plane height off the button that is within range
+     *   - check that collidable + normal ray intersect the bounding sphere
+     */
+    private _isPrimedForInteraction(collidable: Vector3): boolean {
+        // Check if the collidable has an appropriate planar height
+        const heightFromCenter = this._getHeightFromButtonCenter(collidable);
+
+        if (heightFromCenter > this._hoverOffset || heightFromCenter < this._pushThroughBackOffset) {
+            return false;
+        }
+
+        // Check if the collidable or its hover ray lands within the bounding sphere of the button
+        const distanceFromCenter = this._getShortestDistancePointToLine(this._collisionMesh.getAbsolutePosition(),
+                                                                        collidable,
+                                                                        this._collidableFrontDirection);
+        return distanceFromCenter <= this._collisionMesh.getBoundingInfo().boundingSphere.radiusWorld;
+    }
+
+    /*
+     * Returns a Vector3 of the collidable's projected position on the button
+     * Returns the collidable's position if it is inside the button
+     */
+    private _getPointOnButton(collidable: Vector3): Vector3 {
+        const heightFromCenter = this._getHeightFromButtonCenter(collidable);
+
+        if (heightFromCenter <= this._frontOffset && heightFromCenter >= this._backOffset) {
+            // The collidable is in the button, return its position
+            return collidable;
+        }
+        else if (heightFromCenter > this._frontOffset) {
+            // The collidable is in front of the button, project it to the surface
+            const collidableDistanceToFront = (this._frontOffset - heightFromCenter);
+            return collidable.add(this._collidableFrontDirection.scale(collidableDistanceToFront));
+        }
+        else {
+            // The collidable is behind the button, project it to its back
+            const collidableDistanceToBack = (this._backOffset - heightFromCenter);
+            return collidable.add(this._collidableFrontDirection.scale(collidableDistanceToBack));
+        }
+    }
+
+    /*
+     * Updates the distance values.
+     * Should be called when the front direction changes, or the mesh size changes
+     *
+     * Sets the following values:
+     *    _frontOffset
+     *    _backOffset
+     *    _hoverOffset
+     *    _pushThroughBackOffset
+     *
+     * Requires population of:
+     *    _collisionMesh
+     *    _collidableFrontDirection
+     */
+    private _updateDistanceOffsets() {
+        let worldMatrixData = this._getWorldMatrixData(this._collisionMesh);
+
+        if (!worldMatrixData.scale.equalsWithEpsilon(this._lastKnownCollidableScale)) {
+            const collisionMeshPos = this._collisionMesh.getAbsolutePosition();
+
+            this._tempButtonForwardRay.origin = collisionMeshPos;
+            this._tempButtonForwardRay.direction = this._collidableFrontDirection;
+
+            const frontPickingInfo = this._tempButtonForwardRay.intersectsMesh(this._collisionMesh as DeepImmutableObject<AbstractMesh>);
+            this._tempButtonForwardRay.direction = this._tempButtonForwardRay.direction.negate();
+            const backPickingInfo = this._tempButtonForwardRay.intersectsMesh(this._collisionMesh as DeepImmutableObject<AbstractMesh>);
+
+            this._frontOffset = 0;
+            this._backOffset = 0;
+
+            if (frontPickingInfo.hit && backPickingInfo.hit) {
+                this._frontOffset = this._getDistanceOffPlane(frontPickingInfo.pickedPoint!,
+                                                                  this._collidableFrontDirection,
+                                                                  collisionMeshPos);
+                this._backOffset = this._getDistanceOffPlane(backPickingInfo.pickedPoint!,
+                                                                 this._collidableFrontDirection,
+                                                                 collisionMeshPos);
+            }
+
+            // For now, set the hover height equal to the thickness of the button
+            const buttonThickness = this._frontOffset - this._backOffset;
+
+            this._hoverOffset = this._frontOffset + (buttonThickness * 1.25);
+            this._pushThroughBackOffset = this._backOffset - (buttonThickness * 1.5);
+
+            this._lastKnownCollidableScale = this._getWorldMatrixData(this._collisionMesh).scale;
+        }
+    }
+
+    // Returns the distance in front of the center of the button
+    // Returned value is negative when collidable is past the center
+    private _getHeightFromButtonCenter(collidablePos: Vector3) {
+        return this._getDistanceOffPlane(collidablePos, this._collidableFrontDirection, this._collisionMesh.getAbsolutePosition());
+    }
+
+    // Returns the distance from pointOnPlane to point along planeNormal
+    private _getDistanceOffPlane(point: Vector3, planeNormal: Vector3, pointOnPlane: Vector3) {
+        const d = Vector3.Dot(pointOnPlane, planeNormal);
+        const abc = Vector3.Dot(point, planeNormal);
+
+        return abc - d;
+    }
+
+    // Updates the stored state of the button, and fire pointer events
+    private _updateButtonState(id: number, newState: ButtonState, pointOnButton: Vector3) {
+        const dummyPointerId = 0;
+        const buttonIndex = 0; // Left click
+        const buttonStateForId = this._activeInteractions.get(id) || ButtonState.None;
+
+        // Take into account all inputs interacting with the button to avoid state flickering
+        let previousPushDepth = 0;
+        this._activeInteractions.forEach(function(value, key) {
+            previousPushDepth = Math.max(previousPushDepth, value);
+        });
+
+        if (buttonStateForId != newState) {
+            if (newState == ButtonState.None) {
+                this._activeInteractions.delete(id);
+            }
+            else {
+                this._activeInteractions.set(id, newState);
+            }
+        }
+
+        let newPushDepth = 0;
+        this._activeInteractions.forEach(function(value, key) {
+            newPushDepth = Math.max(newPushDepth, value);
+        });
+
+        if (newPushDepth == ButtonState.Press) {
+            if (previousPushDepth == ButtonState.Hover) {
+                this._onPointerDown(this, pointOnButton, dummyPointerId, buttonIndex);
+            }
+            else if (previousPushDepth == ButtonState.Press) {
+                this._onPointerMove(this, pointOnButton);
+            }
+        }
+        else if (newPushDepth == ButtonState.Hover) {
+            if (previousPushDepth == ButtonState.None) {
+                this._onPointerEnter(this);
+            }
+            else if (previousPushDepth == ButtonState.Press) {
+                this._onPointerUp(this, pointOnButton, dummyPointerId, buttonIndex, false);
+            }
+            else {
+                this._onPointerMove(this, pointOnButton);
+            }
+        }
+        else if (newPushDepth == ButtonState.None) {
+            if (previousPushDepth == ButtonState.Hover) {
+                this._onPointerOut(this);
+            }
+            else if (previousPushDepth == ButtonState.Press) {
+                this._onPointerUp(this, pointOnButton, dummyPointerId, buttonIndex, false);
+                this._onPointerOut(this);
+            }
+        }
+    }
+
+    // Decides whether to change button state based on the planar depth of the input source
+    /** @hidden */
+    public _collisionCheckForStateChange(mesh: AbstractMesh) {
+        if (this._collidableInitialized) {
+            this._updateDistanceOffsets();
+
+            const collidablePosition = mesh.getAbsolutePosition();
+            const inRange = this._isPrimedForInteraction(collidablePosition);
+
+            const uniqueId = mesh.uniqueId;
+
+            let activeInteraction = this._activeInteractions.get(uniqueId);
+            if (inRange) {
+                const pointOnButton = this._getPointOnButton(collidablePosition);
+                const heightFromCenter = this._getHeightFromButtonCenter(collidablePosition);
+                const flickerDelta = 0.003;
+
+                this._lastTouchPoint = pointOnButton;
+
+                const isGreater = function (compareHeight: number) {
+                    return heightFromCenter >= (compareHeight + flickerDelta);
+                };
+
+                const isLower = function (compareHeight: number) {
+                    return heightFromCenter <= (compareHeight - flickerDelta);
+                };
+
+                // Update button state and fire events
+                switch (activeInteraction || ButtonState.None) {
+                    case ButtonState.None:
+                        if (isGreater(this._frontOffset) &&
+                            isLower(this._hoverOffset)) {
+                            this._updateButtonState(uniqueId, ButtonState.Hover, pointOnButton);
+                        }
+
+                        break;
+                    case ButtonState.Hover:
+                        if (isGreater(this._hoverOffset)) {
+                            this._updateButtonState(uniqueId, ButtonState.None, pointOnButton);
+                        }
+                        else if (isLower(this._frontOffset)) {
+                            this._updateButtonState(uniqueId, ButtonState.Press, pointOnButton);
+                        }
+
+                        break;
+                    case ButtonState.Press:
+                        if (isGreater(this._frontOffset)) {
+                            this._updateButtonState(uniqueId, ButtonState.Hover, pointOnButton);
+                        }
+                        else if (isLower(this._pushThroughBackOffset)) {
+                            this._updateButtonState(uniqueId, ButtonState.None, pointOnButton);
+                        }
+
+                        break;
+                }
+
+                this._previousHeight.set(uniqueId, heightFromCenter);
+            }
+            else if ((activeInteraction != undefined) && (activeInteraction != ButtonState.None)) {
+                this._updateButtonState(uniqueId, ButtonState.None, this._lastTouchPoint);
+                this._previousHeight.delete(uniqueId);
+            }
+        }
+    }
+
+    protected _getTypeName(): string {
+        return "TouchButton3D";
+    }
+
+    // Mesh association
+    protected _createNode(scene: Scene): TransformNode {
+        return super._createNode(scene);
+    }
+
+    /**
+     * Releases all associated resources
+     */
+    public dispose() {
+        super.dispose();
+
+        if (this._collisionMesh) {
+            this._collisionMesh.dispose();
+        }
+    }
+}

+ 364 - 0
gui/src/3D/controls/touchHolographicButton.ts

@@ -0,0 +1,364 @@
+import { Nullable } from "babylonjs/types";
+import { Observer } from "babylonjs/Misc/observable";
+import { Vector3 } from "babylonjs/Maths/math.vector";
+import { StandardMaterial } from "babylonjs/Materials/standardMaterial";
+import { TransformNode } from "babylonjs/Meshes/transformNode";
+import { Mesh } from "babylonjs/Meshes/mesh";
+import { PlaneBuilder } from "babylonjs/Meshes/Builders/planeBuilder";
+import { BoxBuilder } from "babylonjs/Meshes/Builders/boxBuilder";
+import { FadeInOutBehavior } from "babylonjs/Behaviors/Meshes/fadeInOutBehavior";
+import { Scene } from "babylonjs/scene";
+
+import { FluentMaterial } from "../materials/fluentMaterial";
+import { StackPanel } from "../../2D/controls/stackPanel";
+import { Image } from "../../2D/controls/image";
+import { TextBlock } from "../../2D/controls/textBlock";
+import { AdvancedDynamicTexture } from "../../2D/advancedDynamicTexture";
+import { Control3D } from "./control3D";
+import { Color3 } from 'babylonjs/Maths/math.color';
+
+import { TouchButton3D } from "./touchButton3D";
+
+/**
+ * Class used to create a holographic button in 3D
+ */
+export class TouchHolographicButton extends TouchButton3D {
+    private _backPlate: Mesh;
+    private _textPlate: Mesh;
+    private _frontPlate: Mesh;
+    private _text: string;
+    private _imageUrl: string;
+    private _shareMaterials = true;
+    private _frontMaterial: FluentMaterial;
+    private _backMaterial: FluentMaterial;
+    private _plateMaterial: StandardMaterial;
+    private _pickedPointObserver: Nullable<Observer<Nullable<Vector3>>>;
+
+    // Tooltip
+    private _tooltipFade: Nullable<FadeInOutBehavior>;
+    private _tooltipTextBlock: Nullable<TextBlock>;
+    private _tooltipTexture: Nullable<AdvancedDynamicTexture>;
+    private _tooltipMesh: Nullable<Mesh>;
+    private _tooltipHoverObserver: Nullable<Observer<Control3D>>;
+    private _tooltipOutObserver: Nullable<Observer<Control3D>>;
+
+    private _disposeTooltip() {
+        this._tooltipFade = null;
+        if (this._tooltipTextBlock) {
+            this._tooltipTextBlock.dispose();
+        }
+        if (this._tooltipTexture) {
+            this._tooltipTexture.dispose();
+        }
+        if (this._tooltipMesh) {
+            this._tooltipMesh.dispose();
+        }
+        this.onPointerEnterObservable.remove(this._tooltipHoverObserver);
+        this.onPointerOutObservable.remove(this._tooltipOutObserver);
+    }
+
+    /**
+     * Rendering ground id of all the mesh in the button
+     */
+    public set renderingGroupId(id: number) {
+        this._backPlate.renderingGroupId = id;
+        this._textPlate.renderingGroupId = id;
+        this._frontPlate.renderingGroupId = id;
+
+        if (this._tooltipMesh) {
+            this._tooltipMesh.renderingGroupId = id;
+        }
+    }
+    public get renderingGroupId(): number {
+        return this._backPlate.renderingGroupId;
+    }
+
+    /**
+     * Text to be displayed on the tooltip shown when hovering on the button. When set to null tooltip is disabled. (Default: null)
+     */
+    public set tooltipText(text: Nullable<string>) {
+        if (!text) {
+            this._disposeTooltip();
+            return;
+        }
+        if (!this._tooltipFade) {
+            // Create tooltip with mesh and text
+            this._tooltipMesh = PlaneBuilder.CreatePlane("", { size: 1 }, this._backPlate._scene);
+            var tooltipBackground = PlaneBuilder.CreatePlane("", { size: 1, sideOrientation: Mesh.DOUBLESIDE }, this._backPlate._scene);
+            var mat = new StandardMaterial("", this._backPlate._scene);
+            mat.diffuseColor = Color3.FromHexString("#212121");
+            tooltipBackground.material = mat;
+            tooltipBackground.isPickable = false;
+            this._tooltipMesh.addChild(tooltipBackground);
+            tooltipBackground.position.z = 0.05;
+            this._tooltipMesh.scaling.y = 1 / 3;
+            this._tooltipMesh.position.y = 0.7;
+            this._tooltipMesh.position.z = -0.15;
+            this._tooltipMesh.isPickable = false;
+            this._tooltipMesh.parent = this._backPlate;
+
+            // Create text texture for the tooltip
+            this._tooltipTexture = AdvancedDynamicTexture.CreateForMesh(this._tooltipMesh);
+            this._tooltipTextBlock = new TextBlock();
+            this._tooltipTextBlock.scaleY = 3;
+            this._tooltipTextBlock.color = "white";
+            this._tooltipTextBlock.fontSize = 130;
+            this._tooltipTexture.addControl(this._tooltipTextBlock);
+
+            // Add hover action to tooltip
+            this._tooltipFade = new FadeInOutBehavior();
+            this._tooltipFade.delay = 500;
+            this._tooltipMesh.addBehavior(this._tooltipFade);
+            this._tooltipHoverObserver = this.onPointerEnterObservable.add(() => {
+                if (this._tooltipFade) {
+                    this._tooltipFade.fadeIn(true);
+                }
+            });
+            this._tooltipOutObserver = this.onPointerOutObservable.add(() => {
+                if (this._tooltipFade) {
+                    this._tooltipFade.fadeIn(false);
+                }
+            });
+        }
+        if (this._tooltipTextBlock) {
+            this._tooltipTextBlock.text = text;
+        }
+    }
+
+    public get tooltipText() {
+        if (this._tooltipTextBlock) {
+            return this._tooltipTextBlock.text;
+        }
+        return null;
+    }
+
+    /**
+     * Gets or sets text for the button
+     */
+    public get text(): string {
+        return this._text;
+    }
+
+    public set text(value: string) {
+        if (this._text === value) {
+            return;
+        }
+
+        this._text = value;
+        this._rebuildContent();
+    }
+
+    /**
+     * Gets or sets the image url for the button
+     */
+    public get imageUrl(): string {
+        return this._imageUrl;
+    }
+
+    public set imageUrl(value: string) {
+        if (this._imageUrl === value) {
+            return;
+        }
+
+        this._imageUrl = value;
+        this._rebuildContent();
+    }
+
+    /**
+     * Gets the back material used by this button
+     */
+    public get backMaterial(): FluentMaterial {
+        return this._backMaterial;
+    }
+
+    /**
+     * Gets the front material used by this button
+     */
+    public get frontMaterial(): FluentMaterial {
+        return this._frontMaterial;
+    }
+
+    /**
+     * Gets the plate material used by this button
+     */
+    public get plateMaterial(): StandardMaterial {
+        return this._plateMaterial;
+    }
+
+    /**
+     * Gets a boolean indicating if this button shares its material with other HolographicButtons
+     */
+    public get shareMaterials(): boolean {
+        return this._shareMaterials;
+    }
+
+    /**
+     * Creates a new button
+     * @param name defines the control name
+     */
+    constructor(name?: string, shareMaterials = true) {
+        super(name);
+
+        this._shareMaterials = shareMaterials;
+
+        // Default animations
+        this.pointerEnterAnimation = () => {
+            if (!this.mesh) {
+                return;
+            }
+            this._frontPlate.setEnabled(true);
+        };
+
+        this.pointerOutAnimation = () => {
+            if (!this.mesh) {
+                return;
+            }
+            this._frontPlate.setEnabled(false);
+        };
+    }
+
+    protected _getTypeName(): string {
+        return "TouchHolographicButton";
+    }
+
+    private _rebuildContent(): void {
+        this._disposeFacadeTexture();
+
+        let panel = new StackPanel();
+        panel.isVertical = true;
+
+        if (this._imageUrl) {
+            let image = new Image();
+            image.source = this._imageUrl;
+            image.paddingTop = "40px";
+            image.height = "180px";
+            image.width = "100px";
+            image.paddingBottom = "40px";
+            panel.addControl(image);
+        }
+
+        if (this._text) {
+            let text = new TextBlock();
+            text.text = this._text;
+            text.color = "white";
+            text.height = "30px";
+            text.fontSize = 24;
+            panel.addControl(text);
+        }
+
+        if (this._frontPlate) {
+            this.content = panel;
+        }
+    }
+
+    // Mesh association
+    protected _createNode(scene: Scene): TransformNode {
+        this._backPlate = BoxBuilder.CreateBox(this.name + "BackMesh", {
+            width: 1.0,
+            height: 1.0,
+            depth: 0.08
+        }, scene);
+
+        this._frontPlate = BoxBuilder.CreateBox(this.name + "FrontMesh", {
+            width: 1.0,
+            height: 1.0,
+            depth: 0.4
+        }, scene);
+
+        this._frontPlate.parent = this._backPlate;
+        this._frontPlate.position.z = -0.08;
+        this._frontPlate.isPickable = false;
+        this._frontPlate.setEnabled(false);
+
+        this._textPlate = <Mesh>super._createNode(scene);
+        this._textPlate.parent = this._backPlate;
+        this._textPlate.position.z = -0.08;
+        this._textPlate.isPickable = false;
+
+        this.collisionMesh = this._frontPlate;
+        this.collidableFrontDirection = this._frontPlate.forward.negate(); // Mesh is facing the wrong way
+
+        return this._backPlate;
+    }
+
+    protected _applyFacade(facadeTexture: AdvancedDynamicTexture) {
+        this._plateMaterial.emissiveTexture = facadeTexture;
+        this._plateMaterial.opacityTexture = facadeTexture;
+    }
+
+    private _createBackMaterial(mesh: Mesh) {
+        this._backMaterial = new FluentMaterial(this.name + "Back Material", mesh.getScene());
+        this._backMaterial.renderHoverLight = true;
+        this._backMaterial.albedoColor = new Color3(0.1, 0.1, 0.4);
+        this._pickedPointObserver = this._host.onPickedPointChangedObservable.add((pickedPoint) => {
+            if (pickedPoint) {
+                this._backMaterial.hoverPosition = pickedPoint;
+                this._backMaterial.hoverColor.a = 1.0;
+            } else {
+                this._backMaterial.hoverColor.a = 0;
+            }
+        });
+    }
+
+    private _createFrontMaterial(mesh: Mesh) {
+        this._frontMaterial = new FluentMaterial(this.name + "Front Material", mesh.getScene());
+        this._frontMaterial.innerGlowColorIntensity = 0; // No inner glow
+        this._frontMaterial.alpha = 0.3; // Additive
+        this._frontMaterial.renderBorders = false;
+    }
+
+    private _createPlateMaterial(mesh: Mesh) {
+        this._plateMaterial = new StandardMaterial(this.name + "Plate Material", mesh.getScene());
+        this._plateMaterial.specularColor = Color3.Black();
+    }
+
+    protected _affectMaterial(mesh: Mesh) {
+        // Back
+        if (this._shareMaterials) {
+            if (!this._host._touchSharedMaterials["backFluentMaterial"]) {
+                this._createBackMaterial(mesh);
+                this._host._touchSharedMaterials["backFluentMaterial"] = this._backMaterial;
+            } else {
+                this._backMaterial = this._host._touchSharedMaterials["backFluentMaterial"] as FluentMaterial;
+            }
+
+            // Front
+            if (!this._host._touchSharedMaterials["frontFluentMaterial"]) {
+                this._createFrontMaterial(mesh);
+                this._host._touchSharedMaterials["frontFluentMaterial"] = this._frontMaterial;
+            } else {
+                this._frontMaterial = this._host._touchSharedMaterials["frontFluentMaterial"] as FluentMaterial;
+            }
+        } else {
+            this._createBackMaterial(mesh);
+            this._createFrontMaterial(mesh);
+        }
+
+        this._createPlateMaterial(mesh);
+        this._backPlate.material = this._backMaterial;
+        this._frontPlate.material = this._frontMaterial;
+        this._textPlate.material = this._plateMaterial;
+
+        this._rebuildContent();
+    }
+
+    /**
+     * Releases all associated resources
+     */
+    public dispose() {
+        super.dispose(); // will dispose main mesh ie. back plate
+
+        this._disposeTooltip();
+
+        if (!this.shareMaterials) {
+            this._backMaterial.dispose();
+            this._frontMaterial.dispose();
+            this._plateMaterial.dispose();
+
+            if (this._pickedPointObserver) {
+                this._host.onPickedPointChangedObservable.remove(this._pickedPointObserver);
+                this._pickedPointObserver = null;
+            }
+        }
+    }
+}

+ 81 - 0
gui/src/3D/controls/touchMeshButton3D.ts

@@ -0,0 +1,81 @@
+import { TransformNode } from "babylonjs/Meshes/transformNode";
+import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
+import { Mesh } from "babylonjs/Meshes/mesh";
+import { Scene } from "babylonjs/scene";
+
+import { TouchButton3D } from "./touchButton3D";
+
+/**
+ * Class used to create an interactable object. It's a touchable 3D button using a mesh coming from the current scene
+ */
+export class TouchMeshButton3D extends TouchButton3D {
+    /** @hidden */
+    protected _currentMesh: Mesh;
+
+    /**
+     * Creates a new 3D button based on a mesh
+     * @param mesh mesh to become a 3D button
+     * @param collisionMesh mesh to track collisions with
+     * @param name defines the control name
+     */
+    constructor(mesh: Mesh, options: {collisionMesh: Mesh, useDynamicMesh?: boolean}, name?: string) {
+        if (options.useDynamicMesh) {
+            super(name, options.collisionMesh);
+        }
+        else {
+            let newCollisionMesh = options.collisionMesh.clone("", options.collisionMesh.parent);
+            newCollisionMesh.isVisible = false;
+            super(name, newCollisionMesh);
+        }
+
+        this._currentMesh = mesh;
+
+        /**
+         * Provides a default behavior on hover/out & up/down
+         * Override those function to create your own desired behavior specific to your mesh
+         */
+        this.pointerEnterAnimation = () => {
+            if (!this.mesh) {
+                return;
+            }
+            this.mesh.scaling.scaleInPlace(1.1);
+        };
+
+        this.pointerOutAnimation = () => {
+            if (!this.mesh) {
+                return;
+            }
+            this.mesh.scaling.scaleInPlace(1.0 / 1.1);
+        };
+
+        this.pointerDownAnimation = () => {
+            if (!this.mesh) {
+                return;
+            }
+            this.mesh.scaling.scaleInPlace(0.95);
+        };
+
+        this.pointerUpAnimation = () => {
+            if (!this.mesh) {
+                return;
+            }
+            this.mesh.scaling.scaleInPlace(1.0 / 0.95);
+        };
+    }
+
+    protected _getTypeName(): string {
+        return "TouchMeshButton3D";
+    }
+
+    // Mesh association
+    protected _createNode(scene: Scene): TransformNode {
+        this._currentMesh.getChildMeshes().forEach((mesh) => {
+            mesh.metadata = this;
+        });
+
+        return this._currentMesh;
+    }
+
+    protected _affectMaterial(mesh: AbstractMesh) {
+    }
+}

+ 52 - 0
gui/src/3D/gui3DManager.ts

@@ -11,6 +11,7 @@ import { IDisposable, Scene } from "babylonjs/scene";
 
 
 import { Container3D } from "./controls/container3D";
 import { Container3D } from "./controls/container3D";
 import { Control3D } from "./controls/control3D";
 import { Control3D } from "./controls/control3D";
+import { TouchButton3D } from "./controls/touchButton3D";
 
 
 /**
 /**
  * Class used to manage 3D user interface
  * Class used to manage 3D user interface
@@ -23,6 +24,7 @@ export class GUI3DManager implements IDisposable {
     private _rootContainer: Container3D;
     private _rootContainer: Container3D;
     private _pointerObserver: Nullable<Observer<PointerInfo>>;
     private _pointerObserver: Nullable<Observer<PointerInfo>>;
     private _pointerOutObserver: Nullable<Observer<number>>;
     private _pointerOutObserver: Nullable<Observer<number>>;
+    private _touchableButtons = new Set<TouchButton3D>();
     /** @hidden */
     /** @hidden */
     public _lastPickedControl: Control3D;
     public _lastPickedControl: Control3D;
     /** @hidden */
     /** @hidden */
@@ -39,6 +41,9 @@ export class GUI3DManager implements IDisposable {
     /** @hidden */
     /** @hidden */
     public _sharedMaterials: { [key: string]: Material } = {};
     public _sharedMaterials: { [key: string]: Material } = {};
 
 
+    /** @hidden */
+    public _touchSharedMaterials:  { [key: string]: Material } = {};
+
     /** Gets the hosting scene */
     /** Gets the hosting scene */
     public get scene(): Scene {
     public get scene(): Scene {
         return this._scene;
         return this._scene;
@@ -151,6 +156,19 @@ export class GUI3DManager implements IDisposable {
         return true;
         return true;
     }
     }
 
 
+    private _processTouchControls = () => {
+        let utilityLayerScene = this._utilityLayer ? this._utilityLayer.utilityLayerScene : null;
+        if (utilityLayerScene) {
+            const touchMeshes = utilityLayerScene.getMeshesByTags("touchEnabled");
+
+            this._touchableButtons.forEach(function (button: TouchButton3D) {
+                touchMeshes.forEach(function (mesh: AbstractMesh) {
+                    button._collisionCheckForStateChange(mesh);
+                });
+            });
+        }
+    }
+
     /**
     /**
      * Gets the root container
      * Gets the root container
      */
      */
@@ -174,6 +192,16 @@ export class GUI3DManager implements IDisposable {
      */
      */
     public addControl(control: Control3D): GUI3DManager {
     public addControl(control: Control3D): GUI3DManager {
         this._rootContainer.addControl(control);
         this._rootContainer.addControl(control);
+
+        let utilityLayerScene = this._utilityLayer ? this._utilityLayer.utilityLayerScene : null;
+        if (utilityLayerScene && (control instanceof TouchButton3D)) {
+            if (this._touchableButtons.size == 0) {
+                utilityLayerScene.registerBeforeRender(this._processTouchControls);
+            }
+
+            this._touchableButtons.add(control as TouchButton3D);
+        }
+
         return this;
         return this;
     }
     }
 
 
@@ -184,6 +212,16 @@ export class GUI3DManager implements IDisposable {
      */
      */
     public removeControl(control: Control3D): GUI3DManager {
     public removeControl(control: Control3D): GUI3DManager {
         this._rootContainer.removeControl(control);
         this._rootContainer.removeControl(control);
+
+        let utilityLayerScene = this._utilityLayer ? this._utilityLayer.utilityLayerScene : null;
+        if (utilityLayerScene && (control instanceof TouchButton3D)) {
+            this._touchableButtons.delete(control);
+
+            if (this._touchableButtons.size == 0) {
+                utilityLayerScene.unregisterBeforeRender(this._processTouchControls);
+            }
+        }
+
         return this;
         return this;
     }
     }
 
 
@@ -203,6 +241,16 @@ export class GUI3DManager implements IDisposable {
 
 
         this._sharedMaterials = {};
         this._sharedMaterials = {};
 
 
+        for (var materialName in this._touchSharedMaterials) {
+            if (!this._touchSharedMaterials.hasOwnProperty(materialName)) {
+                continue;
+            }
+
+            this._touchSharedMaterials[materialName].dispose();
+        }
+
+        this._touchSharedMaterials = {};
+
         if (this._pointerOutObserver && this._utilityLayer) {
         if (this._pointerOutObserver && this._utilityLayer) {
             this._utilityLayer.onPointerOutObservable.remove(this._pointerOutObserver);
             this._utilityLayer.onPointerOutObservable.remove(this._pointerOutObserver);
             this._pointerOutObserver = null;
             this._pointerOutObserver = null;
@@ -213,6 +261,10 @@ export class GUI3DManager implements IDisposable {
         let utilityLayerScene = this._utilityLayer ? this._utilityLayer.utilityLayerScene : null;
         let utilityLayerScene = this._utilityLayer ? this._utilityLayer.utilityLayerScene : null;
 
 
         if (utilityLayerScene) {
         if (utilityLayerScene) {
+            if (this._touchableButtons.size != 0) {
+                utilityLayerScene.unregisterBeforeRender(this._processTouchControls);
+            }
+
             if (this._pointerObserver) {
             if (this._pointerObserver) {
                 utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
                 utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
                 this._pointerObserver = null;
                 this._pointerObserver = null;

+ 1 - 0
guiEditor/README-ES6.md

@@ -0,0 +1 @@
+Gui Editor

+ 18 - 0
guiEditor/README.md

@@ -0,0 +1,18 @@
+# Babylon.js Gui Editor
+
+An extension to easily create or update GUI.
+
+## Usage
+### Online method
+Call the method `Show` of the `BABYLON.GuiEditor` class: 
+```
+BABYLON.GuiEditor.Show({hostElement: document.getElementById("host")});
+```
+This method will retrieve dynamically the library `babylon.guiEditor.js`, download it and add
+it to the html page.
+
+### Offline method
+If you don't have access to internet, the gui editor should be imported manually in your HTML page :
+```
+<script src="babylon.guiEditor.js" />
+``` 

+ 3 - 0
guiEditor/imgs/downArrow.svg

@@ -0,0 +1,3 @@
+<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="17" height="17">
+  <path d="M4.21967 8.46967C4.51256 8.17678 4.98744 8.17678 5.28033 8.46967L12 15.1893L18.7197 8.46967C19.0126 8.17678 19.4874 8.17678 19.7803 8.46967C20.0732 8.76256 20.0732 9.23744 19.7803 9.53033L12.5303 16.7803C12.2374 17.0732 11.7626 17.0732 11.4697 16.7803L4.21967 9.53033C3.92678 9.23744 3.92678 8.76256 4.21967 8.46967Z" fill="white" />
+</svg>

+ 43 - 0
guiEditor/public/index-local.html

@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+    <title>Gui Editor - Local Development</title>    
+    <meta name="viewport" content="width=device-width, user-scalable=no">
+    <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
+
+    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+    <script src="../../Tools/DevLoader/BabylonLoader.js"></script>
+    <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css"></link>
+
+    <style>
+        html,
+        body {
+            width: 100%;
+            height: 100%;
+            padding: 0;
+            margin: 0;
+            overflow: hidden;
+        }
+
+        #host-element {
+            width: 100%;
+            height: 100%;            
+        }
+    </style>
+</head>
+
+<body>
+    <div id="host-element">
+    </div>
+    <script>
+        // Load the scripts + map file to allow vscode debug.
+        BABYLONDEVTOOLS.Loader
+            .require("index.js")
+            .load(() => {
+                BABYLONDEVTOOLS.Loader.debugShortcut(engine);
+            });
+    </script>
+</body>
+
+</html>

+ 42 - 0
guiEditor/public/index.html

@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+    <title>Babylon.js Gui Editor</title>
+
+    <meta name="viewport" content="width=device-width, user-scalable=no">
+    <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
+
+    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+    <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css"></link>
+    <script src="https://preview.babylonjs.com/babylon.js"></script>
+    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
+    <script src="https://preview.babylonjs.com/guiEditor/babylon.guiEditor.js"></script>    
+    
+    <style>
+        html,
+        body {
+            width: 100%;
+            height: 100%;
+            padding: 0;
+            margin: 0;
+            overflow: hidden;
+        }
+
+        #host-element {
+            width: 100%;
+            height: 100%;               
+            padding: 0;
+            margin: 0;
+            overflow: hidden;         
+        }
+    </style>
+</head>
+
+<body>    
+    <div id="host-element">
+    </div>
+    <script src="index.js"></script>
+</body>
+
+</html>

+ 116 - 0
guiEditor/public/index.js

@@ -0,0 +1,116 @@
+var snippetUrl = "https://snippet.babylonjs.com";
+var currentSnippetToken;
+var previousHash = "";
+
+var customLoadObservable = new BABYLON.Observable();
+var editorDisplayed = false;
+
+var cleanHash = function () {
+    var splits = decodeURIComponent(location.hash.substr(1)).split("#");
+
+    if (splits.length > 2) {
+        splits.splice(2, splits.length - 2);
+    }
+
+    location.hash = splits.join("#");
+}
+
+var checkHash = function () {
+    if (location.hash) {
+        if (previousHash != location.hash) {
+            cleanHash();
+
+            previousHash = location.hash;
+
+            try {
+                var xmlHttp = new XMLHttpRequest();
+                xmlHttp.onreadystatechange = function () {
+                    if (xmlHttp.readyState == 4) {
+                        if (xmlHttp.status == 200) {
+                            
+                            //TODO: Implement
+                            //var snippet = JSON.parse(JSON.parse(xmlHttp.responseText).jsonPayload);
+                            showEditor();
+                        }
+                    }
+                }
+
+                var hash = location.hash.substr(1);
+                currentSnippetToken = hash.split("#")[0];
+                xmlHttp.open("GET", snippetUrl + "/" + hash.replace("#", "/"));
+                xmlHttp.send();
+            } catch (e) {
+
+            }
+        }
+    }
+
+    setTimeout(checkHash, 200);
+}
+
+var showEditor = function() {
+    editorDisplayed = true;
+    var hostElement = document.getElementById("host-element");
+
+    BABYLON.GuiEditor.Show({
+        hostElement: hostElement,
+        customLoadObservable: customLoadObservable,
+        customSave: {
+            label: "Save as unique URL",
+            action: (data) => {
+                return new Promise((resolve, reject) => {
+                    var xmlHttp = new XMLHttpRequest();
+                    xmlHttp.onreadystatechange = function () {
+                        if (xmlHttp.readyState == 4) {
+                            if (xmlHttp.status == 200) {
+                                var baseUrl = location.href.replace(location.hash, "").replace(location.search, "");
+                                var snippet = JSON.parse(xmlHttp.responseText);
+                                var newUrl = baseUrl + "#" + snippet.id;
+                                currentSnippetToken = snippet.id;
+                                if (snippet.version && snippet.version != "0") {
+                                    newUrl += "#" + snippet.version;
+                                }
+                                location.href = newUrl;
+                                resolve();
+                            }
+                            else {
+                                reject(`Unable to save your gui layout. It may be too large (${(dataToSend.payload.length / 1024).toFixed(2)}`);
+                            }
+                        }
+                    }
+        
+                    xmlHttp.open("POST", snippetUrl + (currentSnippetToken ? "/" + currentSnippetToken : ""), true);
+                    xmlHttp.setRequestHeader("Content-Type", "application/json");
+        
+                    var dataToSend = {
+                        payload : JSON.stringify({
+                            guiLayout: data
+                        }),
+                        name: "",
+                        description: "",
+                        tags: ""
+                    };
+        
+                    xmlHttp.send(JSON.stringify(dataToSend));
+                });
+            }
+        }
+    });
+}
+
+// Let's start
+if (BABYLON.Engine.isSupported()) {
+    var canvas = document.createElement("canvas");
+    var engine = new BABYLON.Engine(canvas, false);
+    var scene = new BABYLON.Scene(engine);
+
+    // Set to default
+    if (!location.hash) {
+        showEditor();
+    }
+}
+else {
+    alert('Babylon.js is not supported.')
+}
+
+checkHash();

+ 211 - 0
guiEditor/src/components/guiList/guiList.scss

@@ -0,0 +1,211 @@
+#guiList {
+    background: #333333;
+    height: 100%;
+    margin: 0;
+    padding: 0;
+    display: grid;
+    width: 100%; 
+    overflow: hidden;
+
+    .panes {
+        overflow: hidden;
+        
+        .pane {
+            color: white;
+
+            overflow: hidden;
+            height: 100%;
+
+            -webkit-user-select: none; 
+            -moz-user-select: none;   
+            -ms-user-select: none;    
+            user-select: none;     
+
+            .filter {
+                display: flex;
+                align-items: stretch;
+        
+                input {
+                    width: 100%;
+                    margin: 10px 10px 5px 10px;
+                    display: block;
+                    border: none;
+                    padding: 0;
+                    border-bottom: solid 1px rgb(51, 122, 183);
+                    background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 96%, rgb(51, 122, 183) 4%);
+                    background-position: -1000px 0;
+                    background-size: 1000px 100%;
+                    background-repeat: no-repeat;  
+                    color:white;    
+                }
+        
+                input:focus  {
+                    box-shadow: none;
+                    outline: none;
+                    background-position: 0 0;
+                }
+
+                input::placeholder {
+                    color: gray;
+                }
+            }
+
+            .list-container {
+                overflow-x: hidden;
+                overflow-y: auto;
+                height: calc(100% - 32px);
+
+                .underline {
+                    border-bottom: 0.5px solid rgba(255, 255, 255, 0.5);
+                }
+
+                .draggableLine {
+                    height: 30px;
+                    display: grid;
+                    align-items: center;
+                    justify-items: stretch;
+                    background: #222222;
+                    cursor: grab;
+                    text-align: center;
+                    margin: 0;
+                    box-sizing: border-box;
+
+                    &:hover {
+                        background: rgb(51, 122, 183);
+                        color: white;
+                    }
+                }
+
+                .nonDraggableLine {
+                    height: 30px;
+                    display: grid;
+                    align-items: center;
+                    justify-items: stretch;
+                    background: #222222;
+                    text-align: center;
+                    margin: 0;
+                    box-sizing: border-box;
+                }
+
+                .withButton {
+                    height: 30px;
+                    position: relative;
+                    .icon {
+                        position: absolute;
+                        right: 4px;
+                        top: 5px;
+                        &:hover {
+                            cursor: pointer;
+                        }
+
+                        .img {
+                            height: 17px;
+                            width: 17px;
+                        }
+                    }
+
+                    .buttonLine {
+                        height: 30px;
+                        display: grid;
+                        align-items: center;
+                        justify-items: stretch;
+                        padding-bottom: 5px;
+                        position: absolute;
+                        right: 0px;
+                        top: 2px;
+                        input[type="file"] {
+                            display: none;
+                        }
+                
+                        .file-upload {            
+                            background: transparent;
+                            border: transparent;
+                            padding: 15px 200px;
+                            opacity: 0.9;
+                            cursor: pointer;
+                            text-align: center;
+                        }
+                
+                        .file-upload:hover {
+                            opacity: 1.0;
+                        }
+                
+                        .file-upload:active {
+                            transform: scale(0.98);
+                            transform-origin: 0.5 0.5;
+                        }
+                
+                        button {
+                            background: transparent;
+                            border: transparent;
+                            margin: 5px 10px 5px 10px;
+                            color:white;
+                            padding: 4px 5px;
+                            opacity: 0.9;
+                        }
+                
+                        button:hover {
+                            opacity: 0.0;
+                        }
+                
+                        button:active {
+                            background: transparent;
+                        }   
+                        
+                        button:focus {
+                            border: transparent;
+                            outline: 0px;
+                        }  
+                    }
+                    
+                }                
+
+                .paneContainer {
+                    margin-top: 3px;
+                    display:grid;
+                    grid-template-rows: 100%;
+                    grid-template-columns: 100%;
+
+                    .paneContainer-content {
+                        grid-row: 1;
+                        grid-column: 1;
+
+                        .header {
+                            display: grid;
+                            grid-template-columns: 1fr auto;
+                            background: #555555;    
+                            height: 30px;   
+                            padding-right: 5px;                        
+                            cursor: pointer;
+                            
+                            .title {                                
+                                border-left: 3px solid transparent;
+                                padding-left: 5px;
+                                grid-column: 1;
+                                display: flex;
+                                align-items: center;
+                            }
+
+                            .collapse {
+                                grid-column: 2;
+                                display: flex;
+                                align-items: center;  
+                                justify-items: center;
+                                transform-origin: center;
+
+                                &.closed {
+                                    transform: rotate(180deg);
+                                }
+                            }                        
+                        }
+
+                        .paneList > div:not(:last-child) {
+                            border-bottom: 1px solid rgba(255, 255, 255, 0.3);
+                        }
+                    }
+                }
+            }    
+        }
+    }
+}
+

+ 89 - 0
guiEditor/src/components/guiList/guiListComponent.tsx

@@ -0,0 +1,89 @@
+import * as React from "react";
+import { GlobalState } from "../../globalState";
+import { LineContainerComponent } from "../../sharedUiComponents/lines/lineContainerComponent";
+import { DraggableLineComponent } from "../../sharedUiComponents/lines/draggableLineComponent";
+import { Observer } from "babylonjs/Misc/observable";
+import { Nullable } from "babylonjs/types";
+
+require("./guiList.scss");
+
+interface IGuiListComponentProps {
+    globalState: GlobalState;
+}
+
+export class GuiListComponent extends React.Component<IGuiListComponentProps, { filter: string }> {
+    private _onResetRequiredObserver: Nullable<Observer<void>>;
+
+    private static _Tooltips: { [key: string]: string } = {
+        Button: "A simple button",
+    };
+
+    constructor(props: IGuiListComponentProps) {
+        super(props);
+
+        this.state = { filter: "" };
+
+        this._onResetRequiredObserver = this.props.globalState.onResetRequiredObservable.add(() => {
+            this.forceUpdate();
+        });
+    }
+
+    componentWillUnmount() {
+        this.props.globalState.onResetRequiredObservable.remove(this._onResetRequiredObserver);
+    }
+
+    filterContent(filter: string) {
+        this.setState({ filter: filter });
+    }
+
+    render() {
+        // Block types used to create the menu from
+        const allBlocks: any = {
+            Buttons: ["TextButton", "ImageButton"],
+            Controls: ["Slider", "Checkbox", "ColorPicker", "VisualKeyboard"],
+            Containers: ["DisplayGrid", "Grid", "StackPanel"],
+            Shapes: ["Ellipse", "Image", "Line", "Rectangle"],
+            Inputs: ["Text", "IntputText", "InputPassword"],
+        };
+
+        // Create node menu
+        var blockMenu = [];
+        for (var key in allBlocks) {
+            var blockList = (allBlocks as any)[key]
+                .filter((b: string) => !this.state.filter || b.toLowerCase().indexOf(this.state.filter.toLowerCase()) !== -1)
+                .sort((a: string, b: string) => a.localeCompare(b))
+                .map((block: any, i: number) => {
+                    return <DraggableLineComponent key={block} data={block} tooltip={GuiListComponent._Tooltips[block] || ""} />;
+                });
+
+            if (blockList.length) {
+                blockMenu.push(
+                    <LineContainerComponent key={key + " blocks"} title={key.replace("__", ": ").replace("_", " ")} closed={false}>
+                        {blockList}
+                    </LineContainerComponent>
+                );
+            }
+        }
+
+        return (
+            <div id="guiList">
+                <div className="panes">
+                    <div className="pane">
+                        <div className="filter">
+                            <input
+                                type="text"
+                                placeholder="Filter"
+                                onFocus={() => (this.props.globalState.blockKeyboardEvents = true)}
+                                onBlur={(evt) => {
+                                    this.props.globalState.blockKeyboardEvents = false;
+                                }}
+                                onChange={(evt) => this.filterContent(evt.target.value)}
+                            />
+                        </div>
+                        <div className="list-container">{blockMenu}</div>
+                    </div>
+                </div>
+            </div>
+        );
+    }
+}

+ 20 - 0
guiEditor/src/components/log/log.scss

@@ -0,0 +1,20 @@
+#log-console {
+    background: #333333;
+    height: 120px;
+    box-sizing: border-box;
+    margin: 0;
+    padding: 10px;
+    width: 100%; 
+    overflow: hidden;
+    overflow-y: auto;
+
+    .log {
+        color: white;
+        font-size: 14px;
+        font-family: 'Courier New', Courier, monospace;
+
+        &.error {
+            color:red;
+        }
+    }
+}

+ 63 - 0
guiEditor/src/components/log/logComponent.tsx

@@ -0,0 +1,63 @@
+
+import * as React from "react";
+import { GlobalState } from '../../globalState';
+import * as ReactDOM from 'react-dom';
+
+require("./log.scss");
+
+interface ILogComponentProps {
+    globalState: GlobalState;
+}
+
+export class LogEntry {
+    constructor(public message: string, public isError: boolean) {
+
+    }
+}
+
+export class LogComponent extends React.Component<ILogComponentProps, { logs: LogEntry[] }> {
+
+    constructor(props: ILogComponentProps) {
+        super(props);
+
+        this.state = { logs: [] };
+    }
+
+    componentDidMount() {
+        this.props.globalState.onLogRequiredObservable.add(log => {
+            let newLogArray = this.state.logs.map(number => number);
+            newLogArray.push(log);
+            this.setState({ logs: newLogArray });
+        });
+    }
+
+    componentDidUpdate() {
+        const logConsole = ReactDOM.findDOMNode(this.refs["log-console"]) as HTMLElement;
+        if (!logConsole) {
+            return;
+        }
+
+        logConsole.scrollTop = logConsole.scrollHeight;
+    }
+
+    render() {
+        var today = new Date();
+        var h = today.getHours();
+        var m = today.getMinutes();
+        var s = today.getSeconds();
+
+        return (
+            <div id="log-console" ref={"log-console"} >
+                {
+                    this.state.logs.map((l, i) => {
+                        return (
+                            <div key={i} className={"log" + (l.isError ? " error" : "")}>
+                                {h + ":" + m + ":" + s+ ": " + l.message}
+                            </div>
+                        )
+                    })
+                }
+            </div>
+        );
+    }
+}

+ 798 - 0
guiEditor/src/components/propertyTab/propertyTab.scss

@@ -0,0 +1,798 @@
+#propertyTab {
+    $line-padding-left: 5px;
+    color:white;
+    background: #333333;
+
+      #header {
+        height: 30px;
+        font-size: 16px;
+        color: white;
+        background: #222222;
+        grid-row: 1;
+        text-align: center;
+        display: grid;
+        grid-template-columns: 30px 1fr;        
+        -webkit-user-select: none; 
+        -moz-user-select: none;   
+        -ms-user-select: none;    
+        user-select: none;                
+
+        #logo {
+            position: relative;
+            grid-column: 1; 
+            width: 24px;
+            height: 24px;
+            left:0;
+            display: flex;
+            align-self: center;   
+            justify-self: center;
+        }        
+
+        #title {
+            grid-column: 2; 
+            display: grid;
+            align-items: center;   
+            text-align: center;
+        }
+    }
+
+    .range {
+        -webkit-appearance: none;
+        width: 120px;
+        height: 6px;
+        background: #d3d3d3;
+        border-radius: 5px;
+        outline: none;
+        opacity: 0.7;
+        -webkit-transition: .2s;
+        transition: opacity .2s;
+    }
+    
+    .range:hover {
+        opacity: 1;
+    }
+    
+    .range::-webkit-slider-thumb {
+        -webkit-appearance: none;
+        appearance: none;
+        width: 14px;
+        height: 14px;
+        border-radius: 50%;
+        background: rgb(51, 122, 183);
+        cursor: pointer;
+    }
+    
+    .range::-moz-range-thumb {
+        width: 14px;
+        height: 14px;
+        border-radius: 50%;
+        background: rgb(51, 122, 183);
+        cursor: pointer;
+    }
+
+    input[type="color"] {
+        -webkit-appearance: none;
+        border: 1px solid rgba(255, 255, 255, 0.5);
+        padding: 0;
+        width: 30px;
+        height: 20px;
+    }
+    input[type="color"]::-webkit-color-swatch-wrapper {
+        padding: 0;
+    }
+    input[type="color"]::-webkit-color-swatch {
+        border: none;
+    }
+
+    .sliderLine {
+        padding-left: $line-padding-left;
+        height: 30px;
+        display: grid;
+        grid-template-rows: 100%;
+        grid-template-columns: 1fr 40px;
+
+        .label { 
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .slider {
+            grid-column: 3;
+            grid-row: 1;
+            margin-right: 5px;
+            width: 90%;
+            display: flex;
+            align-items: center;
+        }
+
+        .floatLine {
+            padding-left: $line-padding-left;
+    
+            .label {
+                grid-column: 1;
+                display: flex;
+                align-items: center;
+            }
+        
+            .short {
+                grid-column: 1; 
+                display: flex;
+                align-items: center;
+                
+                input {
+                    width: 27px;
+                }
+                
+                input::-webkit-outer-spin-button,
+                input::-webkit-inner-spin-button {
+                  -webkit-appearance: none;
+                  margin: 0;
+                }
+    
+                input[type=number] {
+                    -moz-appearance: textfield;
+                }
+            }
+        }  
+    }     
+
+    .textInputLine {
+        padding-left: $line-padding-left;
+        height: 30px;
+        display: grid;
+        grid-template-columns: 1fr 120px auto;
+
+        .label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .value {                        
+            display: flex;
+            align-items: center;
+            grid-column: 2;
+            
+            input {
+                width: calc(100% - 5px);
+            }
+        }
+    }
+    
+    .textInputArea {
+        padding-left: $line-padding-left;
+        height: 100%;
+        display: grid;
+        grid-template-columns: 1fr 120px;
+
+        .label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .value {                        
+            display: flex;
+            align-items: center;
+            grid-column: 2;
+            
+            textarea {
+                width: calc(150% - 5px);
+                margin-left: -50%;
+                height: 40px;
+            }
+        }
+    }
+    
+    .paneContainer {
+        margin-top: 3px;
+        display:grid;
+        grid-template-rows: 100%;
+        grid-template-columns: 100%;
+        
+        .paneList {
+            border-left: 3px solid transparent;
+        }
+
+        &:hover {  
+            .paneList {                      
+                border-left: 3px solid rgba(51, 122, 183, 0.8);
+            }
+
+            .paneContainer-content {
+                .header {
+                    .title {   
+                        border-left: 3px solid rgb(51, 122, 183);
+                    }
+                }
+            }
+        }
+        
+        .paneContainer-highlight-border {
+            grid-row: 1;
+            grid-column: 1;
+            opacity: 1;
+            border: 3px solid red;
+            transition: opacity 250ms;
+            pointer-events: none;
+            
+            &.transparent {
+                opacity: 0;
+            }
+        }
+
+        .paneContainer-content {
+            grid-row: 1;
+            grid-column: 1;
+
+            .header {
+                display: grid;
+                grid-template-columns: 1fr auto;
+                background: #555555;    
+                height: 30px;   
+                padding-right: 5px;                        
+                cursor: pointer;
+                
+                .title {                                
+                    border-left: 3px solid transparent;
+                    padding-left: 5px;
+                    grid-column: 1;
+                    display: flex;
+                    align-items: center;
+                }
+
+                .collapse {
+                    grid-column: 2;
+                    display: flex;
+                    align-items: center;  
+                    justify-items: center;
+                    transform-origin: center;
+
+                    &.closed {
+                        transform: rotate(180deg);
+                    }
+                }                        
+            }
+
+            .paneList > div:not(:last-child) {
+                border-bottom: 0.5px solid rgba(255, 255, 255, 0.1);
+            }
+
+            .fragment > div:not(:last-child)  {
+                border-bottom: 0.5px solid rgba(255, 255, 255, 0.1);
+            }
+        }
+    }
+
+    .color-picker {
+        height: calc(100% - 8px);
+        margin: 4px;
+        width: calc(100% - 8px);
+
+        .color-rect {
+            height: calc(100% - 4px);
+            border: 2px white solid;
+            cursor: pointer;
+            min-height: 18px;
+        }
+
+        .color-picker-cover {
+            position: fixed;
+            top: 0px;
+            right: 0px;
+            bottom: 0px;
+            left: 0px;
+        }
+
+        .color-picker-float {
+            z-index: 2;
+            position: absolute;  
+        }                
+    }
+
+    .gradient-step {
+        display: grid;
+        grid-template-rows: 100%;
+        grid-template-columns: 20px 30px 40px auto 20px 30px;
+        padding-top: 5px;
+        padding-left: 5px;
+        padding-bottom: 5px;
+
+        .step {
+            grid-row: 1;
+            grid-column: 1;
+        }
+            
+        .color {
+            grid-row: 1;
+            grid-column: 2;
+            cursor: pointer;
+        }
+
+        .step-value {       
+            margin-left: 5px;     
+            grid-row: 1;
+            grid-column: 3;
+            text-align: right;
+            margin-right: 5px;
+        }
+
+        .step-slider {            
+            grid-row: 1;
+            grid-column: 4;
+            display: grid;
+            justify-content: stretch;
+            align-content: center;
+            margin-right: -5px;
+            padding-left: 12px;
+
+            input {
+                width: 90%;
+            }
+        }
+
+        .gradient-copy {            
+            grid-row: 1;
+            grid-column: 5;
+            display: grid;
+            align-content: center;
+            justify-content: center;
+ 
+            .img {
+                height: 20px;
+                width: 20px;
+            }
+            .img:hover {
+                cursor: pointer;
+            }
+
+        }
+        .gradient-delete {            
+            grid-row: 1;
+            grid-column: 6;
+            display: grid;
+            align-content: center;
+            justify-content: center;
+            .img {
+                height: 20px;
+                width: 20px;
+            }
+            .img:hover {
+                cursor: pointer;
+            }
+
+        }
+
+    }
+
+    .floatLine {
+        padding-left: $line-padding-left;
+        height: 30px;
+        display: grid;
+        grid-template-columns: 1fr 120px;
+
+
+        .label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .value {
+            grid-column: 2;
+            
+            display: flex;
+            align-items: center;
+            
+            input {
+                width: 110px;
+            }
+        }
+
+        .short {
+            grid-column: 2;
+            
+            display: flex;
+            align-items: center;
+            
+            input {
+                width: 27px;
+            }
+            
+            input::-webkit-outer-spin-button,
+            input::-webkit-inner-spin-button {
+              -webkit-appearance: none;
+              margin: 0;
+            }
+
+            input[type=number] {
+                -moz-appearance: textfield;
+            }
+        }
+    }
+
+    .vector3Line {
+        padding-left:$line-padding-left;                    
+        display: grid;
+
+        .firstLine {
+            display: grid;
+            grid-template-columns: 1fr auto 20px;
+            height: 30px;
+
+            .label {
+                grid-column: 1;
+                display: flex;
+                align-items: center;
+            }
+
+            .vector {
+                grid-column: 2;
+                display: flex;
+                align-items: center;
+                text-align: right;
+                opacity: 0.8;
+            }
+
+            .expand {
+                grid-column: 3;
+                display: grid;
+                align-items: center;
+                justify-items: center;
+                cursor: pointer;
+            }
+        }
+
+        .secondLine {
+            display: grid;
+            padding-right: 5px;  
+            border-left: 1px solid rgb(51, 122, 183);
+
+            .no-right-margin {
+                margin-right: 0;
+            }
+
+            .numeric {
+                display: grid;
+                grid-template-columns: 1fr auto;
+            }
+
+            .numeric-label {
+                text-align: right;
+                grid-column: 1;
+                display: flex;
+                align-items: center;                            
+                justify-self: right;
+                margin-right: 10px;                          
+            }
+
+            .numeric-value {
+                width: 120px;
+                grid-column: 2;
+                display: flex;
+                align-items: center;  
+                border: 1px solid  rgb(51, 122, 183);
+            }                        
+        }
+    }
+
+    .buttonLine {
+        height: 30px;
+        display: grid;
+        align-items: center;
+        justify-items: stretch;
+        padding-bottom: 5px;
+
+        input[type="file"] {
+            display: none;
+        }
+
+        .file-upload {            
+            background: #222222;
+            border: 1px solid rgb(51, 122, 183);
+            margin: 5px 10px;
+            color:white;
+            padding: 4px 5px;
+            padding-top: 0px;
+            opacity: 0.9;
+            cursor: pointer;
+            text-align: center;
+        }
+
+        .file-upload:hover {
+            opacity: 1.0;
+        }
+
+        .file-upload:active {
+            transform: scale(0.98);
+            transform-origin: 0.5 0.5;
+        }
+
+        button {
+            background: #222222;
+            border: 1px solid rgb(51, 122, 183);
+            margin: 5px 10px 5px 10px;
+            color:white;
+            padding: 4px 5px;
+            opacity: 0.9;
+        }
+
+        button:hover {
+            opacity: 1.0;
+        }
+
+        button:active {
+            background: #282828;
+        }   
+        
+        button:focus {
+            border: 1px solid rgb(51, 122, 183);
+            outline: 0px;
+        }  
+    }
+
+    .numeric {
+        padding-left: $line-padding-left;
+        height: 30px;
+        display: grid;
+        grid-template-columns: 1fr 120px auto;
+
+        .numeric-label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .number {                        
+            display: flex;
+            align-items: center;
+            grid-column: 2;
+            height: 10px;
+            .input {
+                width: calc(100% - 5px);
+                height: 10px;
+            }
+        }
+    }
+    
+    .checkBoxLine {
+        padding-left: $line-padding-left;
+        height: 30px;
+        display: grid;
+        grid-template-columns: 1fr auto;
+
+        .label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .checkBox {
+            grid-column: 2;
+            
+            display: flex;
+            align-items: center;
+
+            .lbl {
+                position: relative;
+                display: block;
+                height: 14px;
+                width: 34px;
+                margin-right: 5px;
+                background: #898989;
+                border-radius: 100px;
+                cursor: pointer;
+                transition: all 0.3s ease;
+            }
+
+            .lbl:after {
+                position: absolute;
+                left: 3px;
+                top: 2px;
+                display: block;
+                width: 10px;
+                height: 10px;
+                border-radius: 100px;
+                background: #fff;
+                box-shadow: 0px 3px 3px rgba(0,0,0,0.05);
+                content: '';
+                transition: all 0.15s ease;
+            }
+
+            .lbl:active:after { 
+                transform: scale(1.15, 0.85); 
+            }
+
+            .cbx:checked ~ label { 
+                background: rgb(51, 122, 183);
+            }
+
+            .cbx:checked ~ label:after {
+                left: 20px;
+                background: rgb(22, 73, 117);
+            }
+
+            .cbx:checked ~ label.disabled { 
+                background: rgb(22, 73, 117);
+                cursor: pointer;
+            }
+
+            .cbx:checked ~ label.disabled:after {
+                left: 20px;
+                background: rgb(85, 85, 85);
+                cursor: pointer;
+            }
+
+            .cbx ~ label.disabled {
+                background: rgb(85, 85, 85);
+                cursor: pointer;
+            }
+
+            .hidden { 
+                display: none; 
+            }               
+        }                    
+    }  
+
+    .listLine {
+        padding-left: $line-padding-left;
+        height: 30px;
+        display: grid;
+        grid-template-columns: 1fr auto;
+
+
+        .label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .options {
+            grid-column: 2;
+            
+            display: flex;
+            align-items: center;   
+            margin-right: 5px;
+
+            select {
+                width: 115px;
+            }
+        }                    
+    }  
+                    
+    .color3Line {
+        padding-left: $line-padding-left;
+        display: grid;
+
+        .firstLine {
+            height: 30px;
+            display: grid;
+            grid-template-columns: 1fr auto 20px 20px;
+
+            .label {
+                grid-column: 1;
+                display: flex;
+                align-items: center;
+            }
+
+            .color3 {
+                grid-column: 2;                
+                width: 50px;
+                
+                display: flex;
+                align-items: center;            
+                
+                input {
+                    margin-right: 5px;
+                }
+            }
+
+            .copy {
+                grid-column: 3;
+                display: grid;
+                align-items: center;
+                justify-items: center;
+                cursor: pointer;
+                
+                img {
+                    height: 100%;
+                    width: 20px;
+                }
+            }
+
+            .expand {
+                grid-column: 4;
+                display: grid;
+                align-items: center;
+                justify-items: center;
+                cursor: pointer;
+
+                img {
+                    height: 100%;
+                    width: 20px;
+                }
+            }
+        }   
+
+        .secondLine {
+            display: grid;
+            padding-right: 5px;  
+            border-left: 1px solid rgb(51, 122, 183);
+
+            .numeric {
+                display: grid;
+                grid-template-columns: 1fr auto;
+            }
+
+            .numeric-label {
+                text-align: right;
+                grid-column: 1;
+                display: flex;
+                align-items: center;                            
+                justify-self: right;
+                margin-right: 10px;                          
+            }
+
+            .numeric-value {
+                width: 120px;
+                grid-column: 2;
+                display: flex;
+                align-items: center;  
+                border: 1px solid  rgb(51, 122, 183);
+            }                        
+        }                  
+    }     
+    
+    .textLine {
+        padding-left: $line-padding-left;
+        height: 30px;
+        display: grid;
+        grid-template-columns: 1fr auto;
+
+        .label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .link-value {
+            grid-column: 2;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            text-align: end;
+            opacity: 0.8;
+            margin:5px;
+            margin-top: 6px;
+            max-width: 140px;
+            text-decoration: underline;
+            cursor: pointer;
+        }
+
+        .value {
+            grid-column: 2;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            text-align: end;
+            opacity: 0.8;
+            margin:5px;
+            margin-top: 6px;
+            max-width: 200px;
+            -webkit-user-select: text; 
+            -moz-user-select: text;   
+            -ms-user-select: text;    
+            user-select: text;                
+
+            &.check {
+                color: green;
+            }
+
+            &.uncheck {
+                color: red;
+            }  
+        }
+    }    
+
+}

+ 251 - 0
guiEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -0,0 +1,251 @@
+
+import * as React from "react";
+import { GlobalState } from '../../globalState';
+import { Nullable } from 'babylonjs/types';
+import { ButtonLineComponent } from '../../sharedUiComponents/lines/buttonLineComponent';
+import { LineContainerComponent } from '../../sharedUiComponents/lines/lineContainerComponent';
+import { FileButtonLineComponent } from '../../sharedUiComponents/lines/fileButtonLineComponent';
+import { Tools } from 'babylonjs/Misc/tools';
+import { CheckBoxLineComponent } from '../../sharedUiComponents/lines/checkBoxLineComponent';
+import { DataStorage } from 'babylonjs/Misc/dataStorage';
+import { GUINode } from '../../diagram/guiNode';
+import { Observer } from 'babylonjs/Misc/observable';
+import { TextLineComponent } from "../../sharedUiComponents/lines/textLineComponent";
+import { SerializationTools } from "../../serializationTools";
+import { Engine } from "babylonjs/Engines/engine";
+import { LockObject } from "../../sharedUiComponents/tabs/propertyGrids/lockObject";
+import { SliderPropertyGridComponent } from "../../sharedUiComponents/tabs/propertyGrids/gui/sliderPropertyGridComponent";
+import { Slider } from "babylonjs-gui/2D/controls/sliders/slider";
+
+require("./propertyTab.scss");
+
+interface IPropertyTabComponentProps {
+    globalState: GlobalState;
+}
+
+interface IPropertyTabComponentState {
+    currentNode: Nullable<GUINode>;
+ }
+
+export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, IPropertyTabComponentState> {
+    private _onBuiltObserver: Nullable<Observer<void>>;
+    private _timerIntervalId: number;
+    private _lockObject = new LockObject();
+    constructor(props: IPropertyTabComponentProps) {
+        super(props);
+
+        this.state = { currentNode: null};
+    }
+
+    timerRefresh() {
+        if (!this._lockObject.lock) {
+            this.forceUpdate();
+        }
+    }
+
+    componentDidMount() {
+        this._timerIntervalId = window.setInterval(() => this.timerRefresh(), 500);
+        this.props.globalState.onSelectionChangedObservable.add((selection) => {
+            if (selection instanceof GUINode) {
+                this.setState({ currentNode: selection});
+            } else {
+                this.setState({ currentNode: null });
+            }
+        });
+
+        this._onBuiltObserver = this.props.globalState.onBuiltObservable.add(() => {
+            this.forceUpdate();
+        });
+    }
+
+    componentWillUnmount() {
+        window.clearInterval(this._timerIntervalId);
+        this.props.globalState.onBuiltObservable.remove(this._onBuiltObserver);
+    }
+
+
+    load(file: File) {
+        Tools.ReadFile(file, (data) => {
+            let decoder = new TextDecoder("utf-8");
+            SerializationTools.Deserialize(JSON.parse(decoder.decode(data)), this.props.globalState);
+
+            this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+        }, undefined, true);
+    }
+
+    loadFrame(file: File) {
+        Tools.ReadFile(file, (data) => {
+            // get Frame Data from file
+            //let decoder = new TextDecoder("utf-8");
+           // const frameData = JSON.parse(decoder.decode(data));
+           // SerializationTools.AddFrameToMaterial(frameData, this.props.globalState, this.props.globalState.nodeMaterial);
+        }, undefined, true);
+    }
+
+    save() {
+        //let json = SerializationTools.Serialize(this.props.globalState.nodeMaterial, this.props.globalState);
+        //StringTools.DownloadAsFile(this.props.globalState.hostDocument, json, "nodeMaterial.json");
+    }
+
+    customSave() {
+        /*this.props.globalState.onLogRequiredObservable.notifyObservers({message: "Saving your material to Babylon.js snippet server...", isError: false});
+        this.props.globalState.customSave!.action(SerializationTools.Serialize(this.props.globalState.nodeMaterial, this.props.globalState)).then(() => {
+            this.props.globalState.onLogRequiredObservable.notifyObservers({message: "Material saved successfully", isError: false});
+        }).catch((err) => {
+            this.props.globalState.onLogRequiredObservable.notifyObservers({message: err, isError: true});
+        });*/
+    }
+
+    saveToSnippetServer() {
+        /*const material = this.props.globalState.nodeMaterial;
+        const xmlHttp = new XMLHttpRequest();
+
+        let json = SerializationTools.Serialize(material, this.props.globalState);
+
+        xmlHttp.onreadystatechange = () => {
+            if (xmlHttp.readyState == 4) {
+                if (xmlHttp.status == 200) {
+                    var snippet = JSON.parse(xmlHttp.responseText);
+                    const oldId = material.snippetId;
+                    material.snippetId = snippet.id;
+                    if (snippet.version && snippet.version != "0") {
+                        material.snippetId += "#" + snippet.version;
+                    }
+
+                    this.forceUpdate();
+                    if (navigator.clipboard) {
+                        navigator.clipboard.writeText(material.snippetId);
+                    }
+
+                    let windowAsAny = window as any;
+
+                    if (windowAsAny.Playground && oldId) {
+                        windowAsAny.Playground.onRequestCodeChangeObservable.notifyObservers({
+                            regex: new RegExp(oldId, "g"),
+                            replace: material.snippetId
+                        });
+                    }
+
+                    this.props.globalState.hostDocument.defaultView!.alert("NodeMaterial saved with ID: " + material.snippetId + " (please note that the id was also saved to your clipboard)");
+
+                }
+                else {
+                    this.props.globalState.hostDocument.defaultView!.alert(`Unable to save your node material. It may be too large (${(dataToSend.payload.length / 1024).toFixed(2)} KB) because of embedded textures. Please reduce texture sizes or point to a specific url instead of embedding them and try again.`);
+                }
+            }
+        };
+
+        xmlHttp.open("POST", NodeMaterial.SnippetUrl + (material.snippetId ? "/" + material.snippetId : ""), true);
+        xmlHttp.setRequestHeader("Content-Type", "application/json");
+
+        var dataToSend = {
+            payload : JSON.stringify({
+                nodeMaterial: json
+            }),
+            name: "",
+            description: "",
+            tags: ""
+        };
+
+        xmlHttp.send(JSON.stringify(dataToSend));*/
+    }
+
+    loadFromSnippet() {
+        /*const material = this.props.globalState.nodeMaterial;
+        const scene = material.getScene();
+
+        let snippedID = window.prompt("Please enter the snippet ID to use");
+
+        if (!snippedID) {
+            return;
+        }
+
+        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+
+        NodeMaterial.ParseFromSnippetAsync(snippedID, scene, "", material).then(() => {
+            material.build();
+            if (!this.changeMode(this.props.globalState.nodeMaterial!.mode, true, false)) {
+                this.props.globalState.onResetRequiredObservable.notifyObservers();
+            }
+        }).catch((err) => {
+            this.props.globalState.hostDocument.defaultView!.alert("Unable to load your node material: " + err);
+        });*/
+    }
+
+    renderProperties()
+    {
+        var className = this.state.currentNode?.guiControl.getClassName();
+        if (className === "Slider") {
+            const slider = this.state.currentNode?.guiControl as Slider;
+            return (<SliderPropertyGridComponent slider={slider}
+                lockObject={this._lockObject}
+                onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+        }
+        return null;
+    }
+
+    render() {
+        if (this.state.currentNode) {
+            return (
+                <div id="propertyTab">
+                    <div id="header">
+                        <img id="logo" src="https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" />
+                        <div id="title">
+                            GUI EDITOR
+                        </div>
+                    </div>
+                    {this.renderProperties()}
+                </div>
+            );
+        }
+
+        return (
+            <div id="propertyTab">
+                <div id="header">
+                    <img id="logo" src="https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" />
+                    <div id="title">
+                        GUI EDITOR
+                    </div>
+                </div>
+                <div>
+                    <LineContainerComponent title="GENERAL">
+                        <TextLineComponent label="Version" value={Engine.Version}/>
+                        <TextLineComponent label="Help" value="doc.babylonjs.com" underline={true} onLink={() => window.open('https://doc.babylonjs.com', '_blank')}/>
+                        <ButtonLineComponent label="Reset to default" onClick={() => {
+                            this.props.globalState.onResetRequiredObservable.notifyObservers();
+                        }} />
+                    </LineContainerComponent>
+                    <LineContainerComponent title="OPTIONS">
+                        <CheckBoxLineComponent label="Show grid"
+                            isSelected={() => DataStorage.ReadBoolean("ShowGrid", true)}
+                            onSelect={(value: boolean) => {
+                                DataStorage.WriteBoolean("ShowGrid", value);
+                            }}
+                        />
+                    </LineContainerComponent>
+                    <LineContainerComponent title="FILE">
+                        <FileButtonLineComponent label="Load" onClick={(file) => this.load(file)} accept=".json" />
+                        <ButtonLineComponent label="Save" onClick={() => {
+                            this.save();
+                        }} />
+                        {
+                            this.props.globalState.customSave &&
+                            <ButtonLineComponent label={this.props.globalState.customSave!.label} onClick={() => {
+                                this.customSave();
+                            }} />
+                        }
+                    </LineContainerComponent>
+                    {
+                        !this.props.globalState.customSave &&
+                        <LineContainerComponent title="SNIPPET">
+                            <ButtonLineComponent label="Load from snippet server" onClick={() => this.loadFromSnippet()} />
+                            <ButtonLineComponent label="Save to snippet server" onClick={() => {
+                                this.saveToSnippetServer();
+                            }} />
+                        </LineContainerComponent>
+                    }
+                </div>
+            </div>
+        );
+    }
+}

+ 182 - 0
guiEditor/src/diagram/guiNode.ts

@@ -0,0 +1,182 @@
+import { GlobalState } from '../globalState';
+import { Nullable } from 'babylonjs/types';
+import { Observer } from 'babylonjs/Misc/observable';
+import { WorkbenchComponent, FramePortData } from './workbench';
+import { Control } from 'babylonjs-gui/2D/controls/control';
+import { Vector2 } from 'babylonjs/Maths/math.vector';
+
+
+export class GUINode {
+    private _x = 0;
+    private _y = 0;
+    private _gridAlignedX = 0;
+    private _gridAlignedY = 0;    
+    private _globalState: GlobalState;
+    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GUINode | FramePortData>>>;  
+    private _onSelectionBoxMovedObserver: Nullable<Observer<ClientRect | DOMRect>>;   
+    private _onUpdateRequiredObserver: Nullable<Observer<void>>;  
+    private _ownerCanvas: WorkbenchComponent; 
+    private _isSelected: boolean;
+    private _isVisible = true;
+    private _enclosingFrameId = -1;
+
+    public get isVisible() {
+        return this._isVisible;
+    }
+
+    public set isVisible(value: boolean) {
+        this._isVisible = value;
+    }
+
+    public get gridAlignedX() {
+        return this._gridAlignedX;
+    }
+
+    public get gridAlignedY() {
+        return this._gridAlignedY;
+    }
+
+    public get x() {
+        return this._x;
+    }
+
+    public set x(value: number) {
+        if (this._x === value) {
+            return;
+        }
+        this._x = value;
+        
+        this._gridAlignedX = this._ownerCanvas.getGridPosition(value);
+    }
+
+    public get y() {
+        return this._y;
+    }
+
+    public set y(value: number) {
+        if (this._y === value) {
+            return;
+        }
+
+        this._y = value;
+
+        this._gridAlignedY = this._ownerCanvas.getGridPosition(value);
+    }
+
+    public get width() {
+        return this.guiControl.widthInPixels;
+    }
+
+    public get height() {
+        return this.guiControl.heightInPixels;
+    }
+
+    public get id() {
+        return this.guiControl.uniqueId;
+    }
+
+    public get name() {
+        return this.guiControl.name;
+    }
+
+    public get isSelected() {
+        return this._isSelected;
+    }
+
+    public get enclosingFrameId() {
+        return this._enclosingFrameId;
+    }
+
+    public set enclosingFrameId(value: number) {
+        this._enclosingFrameId = value;
+    }
+
+    public set isSelected(value: boolean) {
+        this._isSelected = value;
+
+        if (value) {
+            this._globalState.onSelectionChangedObservable.notifyObservers(this);  
+        }
+    }
+
+    public constructor(globalState: GlobalState, public guiControl: Control) {
+        this._globalState = globalState;
+        this._ownerCanvas = this._globalState.workbench;
+        
+        guiControl.onPointerUpObservable.add(evt => {
+            this.clicked = false;
+            console.log("up");
+        });
+
+        guiControl.onPointerDownObservable.add( evt => {
+            this.clicked = true;
+            this.isSelected = true;
+            console.log("down");
+        }
+        );
+
+        guiControl.onPointerEnterObservable.add( evt => {
+            this._ownerCanvas.isOverGUINode = true;
+            console.log("in");
+        }
+        );
+
+        guiControl.onPointerOutObservable.add( evt => {
+            this._ownerCanvas.isOverGUINode = false;
+            console.log("out");
+        }
+        );
+
+        //TODO: Implement
+        this._onSelectionBoxMovedObserver = this._globalState.onSelectionBoxMoved.add(rect1 => {
+        });
+
+    }
+
+    public cleanAccumulation(useCeil = false) {
+        this.x = this._ownerCanvas.getGridPosition(this.x, useCeil);
+        this.y = this._ownerCanvas.getGridPosition(this.y, useCeil);
+    }
+
+    public clicked: boolean;
+    public _onMove(evt: Vector2, startPos: Vector2) {
+       
+        if(!this.clicked) return false;
+        console.log("moving");
+
+        //TODO: Implement move with zoom factor.
+        let newX = (evt.x - startPos.x) ;// / this._ownerCanvas.zoom;
+        let newY = (evt.y - startPos.y) ;// / this._ownerCanvas.zoom;
+
+        this.x += newX;
+        this.y += newY;  
+
+        return true;
+        //evt.stopPropagation();
+    }
+
+    public updateVisual()
+    {
+        this.guiControl.leftInPixels = this.x;
+        this.guiControl.topInPixels = this.y;
+    }
+
+    public dispose() {
+        // notify frame observers that this node is being deleted
+        this._globalState.onGuiNodeRemovalObservable.notifyObservers(this);
+
+        if (this._onSelectionChangedObserver) {
+            this._globalState.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
+        }
+
+        if (this._onUpdateRequiredObserver) {
+            this._globalState.onUpdateRequiredObservable.remove(this._onUpdateRequiredObserver);
+        }
+
+        if (this._onSelectionBoxMovedObserver) {
+            this._globalState.onSelectionBoxMoved.remove(this._onSelectionBoxMovedObserver);
+        }
+
+        this.guiControl.dispose();   
+    }
+}

+ 113 - 0
guiEditor/src/diagram/properties/genericNodePropertyComponent.tsx

@@ -0,0 +1,113 @@
+
+import * as React from "react";
+import { LineContainerComponent } from '../../sharedUiComponents/lines/lineContainerComponent';
+import { IPropertyComponentProps } from './propertyComponentProps';
+import { CheckBoxLineComponent } from '../../sharedUiComponents/lines/checkBoxLineComponent';
+import { FloatLineComponent } from '../../sharedComponents/floatLineComponent';
+import { SliderLineComponent } from '../../sharedComponents/sliderLineComponent';
+import { PropertyTypeForEdition, IPropertyDescriptionForEdition } from 'babylonjs/Materials/Node/nodeMaterialDecorator';
+
+export class GenericPropertyComponent extends React.Component<IPropertyComponentProps> {
+    constructor(props: IPropertyComponentProps) {
+        super(props);
+    }
+
+    render() {
+        return (
+            <>
+                <GeneralPropertyTabComponent globalState={this.props.globalState} guiControl={this.props.guiControl}/>
+                <GenericPropertyTabComponent globalState={this.props.globalState} guiControl={this.props.guiControl}/>
+            </>
+        );
+    }
+}
+
+export class GeneralPropertyTabComponent extends React.Component<IPropertyComponentProps> {
+    constructor(props: IPropertyComponentProps) {
+        super(props);
+    }
+
+    render() {
+        return (
+            <>
+                <LineContainerComponent title="GENERAL">
+                </LineContainerComponent>
+            </>
+        );
+    }
+}
+
+export class GenericPropertyTabComponent extends React.Component<IPropertyComponentProps> {
+    constructor(props: IPropertyComponentProps) {
+        super(props);
+    }
+
+    forceRebuild(notifiers?: { "rebuild"?: boolean; "update"?: boolean; }) {
+        if (!notifiers || notifiers.update) {
+            this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+        }
+
+        if (!notifiers || notifiers.rebuild) {
+            this.props.globalState.onRebuildRequiredObservable.notifyObservers();
+        }
+    }
+
+    render() {
+        const block = this.props.guiControl,
+              propStore: IPropertyDescriptionForEdition[] = (block as any)._propStore;
+
+        if (!propStore) {
+            return (
+                <>
+                </>
+            );
+        }
+
+        const componentList: { [groupName: string]: JSX.Element[]} = {},
+              groups: string[] = [];
+
+        for (const { propertyName, displayName, type, groupName, options } of propStore) {
+            let components = componentList[groupName];
+
+            if (!components) {
+                components = [];
+                componentList[groupName] = components;
+                groups.push(groupName);
+            }
+
+            switch (type) {
+                case PropertyTypeForEdition.Boolean: {
+                    components.push(
+                        <CheckBoxLineComponent label={displayName} target={this.props.guiControl} propertyName={propertyName} onValueChanged={() => this.forceRebuild(options.notifiers)} />
+                    );
+                    break;
+                }
+                case PropertyTypeForEdition.Float: {
+                    let cantDisplaySlider = (isNaN(options.min as number) || isNaN(options.max as number) || options.min === options.max);
+                    if (cantDisplaySlider) {
+                        components.push(
+                            <FloatLineComponent globalState={this.props.globalState} label={displayName} propertyName={propertyName} target={this.props.guiControl} onChange={() => this.forceRebuild(options.notifiers)} />
+                        );
+                    } else {
+                        components.push(
+                            <SliderLineComponent label={displayName} target={this.props.guiControl} globalState={this.props.globalState} propertyName={propertyName} step={Math.abs((options.max as number) - (options.min as number)) / 100.0} minimum={Math.min(options.min as number, options.max as number)} maximum={options.max as number} onChange={() => this.forceRebuild(options.notifiers)}/>
+                        );
+                    }
+                    break;
+                }
+            }
+        }
+
+        return (
+            <>
+            {
+                groups.map((group) =>
+                    <LineContainerComponent title={group}>
+                        {componentList[group]}
+                    </LineContainerComponent>
+                )
+            }
+            </>
+        );
+    }
+}

+ 7 - 0
guiEditor/src/diagram/properties/propertyComponentProps.ts

@@ -0,0 +1,7 @@
+import { Control } from "babylonjs-gui/2D/controls/control";
+import { GlobalState } from "../../globalState";
+
+export interface IPropertyComponentProps {
+    globalState: GlobalState;
+    guiControl: Control;
+}

+ 541 - 0
guiEditor/src/diagram/workbench.tsx

@@ -0,0 +1,541 @@
+import * as React from "react";
+import { GlobalState } from '../globalState';
+import { GUINode } from './guiNode';
+import * as dagre from 'dagre';
+import { Nullable } from 'babylonjs/types';
+
+import { DataStorage } from 'babylonjs/Misc/dataStorage';
+
+import {Control} from 'babylonjs-gui/2D/controls/control';
+import { AdvancedDynamicTexture } from "babylonjs-gui/2D/advancedDynamicTexture";
+import { Vector2, Vector3 } from "babylonjs/Maths/math.vector";
+import { Engine } from "babylonjs/Engines/engine";
+import { Scene } from "babylonjs/scene";
+import { Color4 } from "babylonjs/Maths/math.color";
+import { FreeCamera } from "babylonjs/Cameras/freeCamera";
+
+require("./workbenchCanvas.scss");
+
+export interface IWorkbenchComponentProps {
+    globalState: GlobalState
+}
+
+export type FramePortData = {
+}
+
+export const isFramePortData = (variableToCheck: any): variableToCheck is FramePortData => {
+    if (variableToCheck) {
+        return (variableToCheck as FramePortData) !== undefined;
+    }
+    else return false;
+}
+
+export class WorkbenchComponent extends React.Component<IWorkbenchComponentProps> {
+    private readonly MinZoom = 0.1;
+    private readonly MaxZoom = 4;
+
+    private _hostCanvas: HTMLDivElement;
+    private _gridCanvas: HTMLDivElement;
+    private _selectionContainer: HTMLDivElement;
+    private _frameContainer: HTMLDivElement;
+    private _svgCanvas: HTMLElement;
+    private _rootContainer: HTMLDivElement;
+    private _guiNodes: GUINode[] = [];
+    private _mouseStartPointX: Nullable<number> = null;
+    private _mouseStartPointY: Nullable<number> = null
+    private _selectionStartX = 0;
+    private _selectionStartY = 0;
+    private _x = 0;
+    private _y = 0;
+    private _zoom = 1;
+    private _selectedGuiNodes: GUINode[] = [];
+    private _gridSize = 20;
+    private _selectionBox: Nullable<HTMLDivElement> = null;    
+    private _frameCandidate: Nullable<HTMLDivElement> = null;
+
+    private _altKeyIsPressed = false;
+    private _ctrlKeyIsPressed = false;
+    private _oldY = -1;
+
+    public _frameIsMoving = false;
+    public _isLoading = false;
+    public isOverGUINode = false;
+
+    public get gridSize() {
+        return this._gridSize;
+    }
+
+    public set gridSize(value: number) {
+        this._gridSize = value;
+        
+        this.updateTransform();
+    }
+
+    public get globalState(){
+        return this.props.globalState;
+    }
+
+    public get nodes() {
+        return this._guiNodes;
+    }
+
+    public get zoom() {
+        return this._zoom;
+    }
+
+    public set zoom(value: number) {
+        if (this._zoom === value) {
+            return;
+        }
+
+        this._zoom = value;
+        
+        this.updateTransform();
+    }    
+
+    public get x() {
+        return this._x;
+    }
+
+    public set x(value: number) {
+        this._x = value;
+        
+        this.updateTransform();
+    }
+
+    public get y() {
+        return this._y;
+    }
+
+    public set y(value: number) {
+        this._y = value;
+        
+        this.updateTransform();
+    }
+
+    public get selectedGuiNodes() {
+        return this._selectedGuiNodes;
+    }
+
+    public get canvasContainer() {
+        return this._gridCanvas;
+    }
+
+    public get hostCanvas() {
+        return this._hostCanvas;
+    }
+
+    public get svgCanvas() {
+        return this._svgCanvas;
+    }
+
+    public get selectionContainer() {
+        return this._selectionContainer;
+    }
+
+    public get frameContainer() {
+        return this._frameContainer;
+    }
+
+    constructor(props: IWorkbenchComponentProps) {
+        super(props);
+
+        props.globalState.onSelectionChangedObservable.add(selection => {  
+            console.log(selection);
+            
+            this.selectedGuiNodes.forEach(element => {
+                element.isSelected = false;
+            }); 
+            if (!selection) {
+                this._selectedGuiNodes = [];
+            } 
+            else {
+                if (selection instanceof GUINode){
+                    if (this._ctrlKeyIsPressed) {
+                        if (this._selectedGuiNodes.indexOf(selection) === -1) {
+                            this._selectedGuiNodes.push(selection);
+                        }
+                    } 
+                    else {              
+                        this._selectedGuiNodes = [selection];
+                    }
+                
+                } 
+            }
+        });
+
+
+        this.props.globalState.hostDocument!.addEventListener("keyup", () => this.onKeyUp(), false);
+        this.props.globalState.hostDocument!.addEventListener("keydown", evt => {
+            this._altKeyIsPressed = evt.altKey;            
+            this._ctrlKeyIsPressed = evt.ctrlKey;
+        }, false);
+        this.props.globalState.hostDocument!.defaultView!.addEventListener("blur", () => {
+            this._altKeyIsPressed = false;
+            this._ctrlKeyIsPressed = false;
+        }, false);     
+
+        // Store additional data to serialization object
+        this.props.globalState.storeEditorData = (editorData) => {
+            editorData.x = this.x;
+            editorData.y = this.y;
+            editorData.zoom = this.zoom;
+        }
+        this.props.globalState.workbench = this;
+    }
+
+    public getGridPosition(position: number, useCeil = false) {
+        let gridSize = this.gridSize;
+		if (gridSize === 0) {
+			return position;
+        }
+        if (useCeil) {
+            return gridSize * Math.ceil(position / gridSize);    
+        }
+		return gridSize * Math.floor(position / gridSize);
+    }
+    
+    public getGridPositionCeil(position: number) {
+        let gridSize = this.gridSize;
+		if (gridSize === 0) {
+			return position;
+		}
+		return gridSize * Math.ceil(position / gridSize);
+	}
+
+    updateTransform() {
+        this._rootContainer.style.transform = `translate(${this._x}px, ${this._y}px) scale(${this._zoom})`;
+
+        if (DataStorage.ReadBoolean("ShowGrid", true)) {
+            this._hostCanvas.style.backgroundSize = `${this._gridSize * this._zoom}px ${this._gridSize * this._zoom}px`;
+            this._hostCanvas.style.backgroundPosition = `${this._x}px ${this._y}px`;
+        } else {
+            this._hostCanvas.style.backgroundSize = `0`;
+        }
+    }
+
+    onKeyUp() {        
+        this._altKeyIsPressed = false;
+        this._ctrlKeyIsPressed = false;
+        this._oldY = -1;
+    }
+
+    findNodeFromGuiElement(guiControl: Control) {
+       return this._guiNodes.filter(n => n.guiControl === guiControl)[0];
+    }
+
+    reset() {
+        for (var node of this._guiNodes) {
+            node.dispose();
+        }
+        this._guiNodes = [];
+        this._gridCanvas.innerHTML = "";
+        this._svgCanvas.innerHTML = "";
+    }
+
+    appendBlock(guiElement: Control) {
+        var newGuiNode = new GUINode(this.props.globalState, guiElement);
+        this._guiNodes.push(newGuiNode);
+        this.globalState.guiTexture.addControl(guiElement);  
+        return newGuiNode;
+    }
+
+    distributeGraph() {
+        this.x = 0;
+        this.y = 0;
+        this.zoom = 1;
+
+        let graph = new dagre.graphlib.Graph();
+        graph.setGraph({});
+        graph.setDefaultEdgeLabel(() => ({}));
+        graph.graph().rankdir = "LR";
+
+        // Build dagre graph
+        this._guiNodes.forEach(node => {
+
+
+            graph.setNode(node.id.toString(), {
+                id: node.id,
+                type: "node",
+                width: node.width,
+                height: node.height
+            });
+        });
+
+        // Distribute
+        dagre.layout(graph);
+
+        // Update graph
+        let dagreNodes = graph.nodes().map(node => graph.node(node));
+        dagreNodes.forEach((dagreNode: any) => {
+            if (!dagreNode) {
+                return;
+            }
+            if (dagreNode.type === "node") {
+                for (var node of this._guiNodes) {
+                    if (node.id === dagreNode.id) {
+                        node.x = dagreNode.x - dagreNode.width / 2;
+                        node.y = dagreNode.y - dagreNode.height / 2;
+                        node.cleanAccumulation();
+                        return;
+                    }
+                }
+                return;
+            }
+        });        
+    }
+
+    componentDidMount() {
+        this._hostCanvas = this.props.globalState.hostDocument.getElementById("workbench-canvas") as HTMLDivElement;
+        this._rootContainer = this.props.globalState.hostDocument.getElementById("workbench-container") as HTMLDivElement;
+        this._gridCanvas = this.props.globalState.hostDocument.getElementById("workbench-canvas-container") as HTMLDivElement;
+        this._svgCanvas = this.props.globalState.hostDocument.getElementById("workbench-svg-container") as HTMLElement;        
+        this._selectionContainer = this.props.globalState.hostDocument.getElementById("selection-container") as HTMLDivElement;   
+        this._frameContainer = this.props.globalState.hostDocument.getElementById("frame-container") as HTMLDivElement;        
+        
+        this.gridSize = DataStorage.ReadNumber("GridSize", 20);
+        this.updateTransform();
+    }    
+
+    onMove(evt: React.PointerEvent) {        
+        // Selection box
+        if (this._selectionBox) {
+            const rootRect = this.canvasContainer.getBoundingClientRect();      
+
+            const localX = evt.pageX - rootRect.left;
+            const localY = evt.pageY - rootRect.top;
+
+            if (localX > this._selectionStartX) {
+                this._selectionBox.style.left = `${this._selectionStartX / this.zoom}px`;
+                this._selectionBox.style.width = `${(localX - this._selectionStartX) / this.zoom}px`;
+            } else {
+                this._selectionBox.style.left = `${localX / this.zoom}px`;
+                this._selectionBox.style.width = `${(this._selectionStartX - localX) / this.zoom}px`;
+            }
+
+            if (localY > this._selectionStartY) {                
+                this._selectionBox.style.top = `${this._selectionStartY / this.zoom}px`;
+                this._selectionBox.style.height = `${(localY - this._selectionStartY) / this.zoom}px`;
+            } else {
+                this._selectionBox.style.top = `${localY / this.zoom}px`;
+                this._selectionBox.style.height = `${(this._selectionStartY - localY) / this.zoom}px`;
+            }
+            
+            this.props.globalState.onSelectionBoxMoved.notifyObservers(this._selectionBox.getBoundingClientRect());
+
+            return;
+        }
+
+        
+        // Zoom with mouse + alt
+        if (this._altKeyIsPressed && evt.buttons === 1) {
+            if (this._oldY < 0) {
+                this._oldY = evt.pageY;
+            }
+
+            let zoomDelta = (evt.pageY - this._oldY) / 10;
+            if (Math.abs(zoomDelta) > 5) {
+                const oldZoom = this.zoom;
+                this.zoom = Math.max(Math.min(this.MaxZoom, this.zoom + zoomDelta / 100), this.MinZoom);
+
+                const boundingRect = evt.currentTarget.getBoundingClientRect();
+                const clientWidth = boundingRect.width;
+                const widthDiff = clientWidth * this.zoom - clientWidth * oldZoom;
+                const clientX = evt.clientX - boundingRect.left;
+        
+                const xFactor = (clientX - this.x) / oldZoom / clientWidth;
+        
+                this.x = this.x - widthDiff * xFactor;
+
+                this._oldY = evt.pageY;      
+            }
+            return;
+        }   
+
+        // Move canvas and/or guiNodes
+        if (this._mouseStartPointX != null && this._mouseStartPointY != null) {
+
+            var x = this._mouseStartPointX;
+            var y = this._mouseStartPointY;
+            let selected = false;
+            this.selectedGuiNodes.forEach(element => {
+                selected = element._onMove(new Vector2(evt.clientX, evt.clientY), 
+                new Vector2( x, y)) || selected;
+            });
+
+            if(!selected) {
+                this._rootContainer.style.cursor = "move";
+                this.x += evt.clientX - this._mouseStartPointX;
+                this.y += evt.clientY - this._mouseStartPointY;
+            }
+            this._mouseStartPointX = evt.clientX;
+            this._mouseStartPointY = evt.clientY;
+        }
+    }
+
+    onDown(evt: React.PointerEvent<HTMLElement>) {
+        this._rootContainer.setPointerCapture(evt.pointerId);
+
+        //TODO: Inplement group selection
+        // Selection?
+        /*if (evt.currentTarget === this._hostCanvas && evt.ctrlKey) {
+            this._selectionBox = this.props.globalState.hostDocument.createElement("div");
+            this._selectionBox.classList.add("selection-box");
+            this._selectionContainer.appendChild(this._selectionBox);
+
+            const rootRect = this.canvasContainer.getBoundingClientRect();      
+            this._selectionStartX = (evt.pageX - rootRect.left);
+            this._selectionStartY = (evt.pageY - rootRect.top);
+            this._selectionBox.style.left = `${this._selectionStartX / this.zoom}px`;
+            this._selectionBox.style.top = `${this._selectionStartY / this.zoom}px`;
+            this._selectionBox.style.width = "0px";
+            this._selectionBox.style.height = "0px";
+            return;
+        }*/
+        console.log('workbench click');
+        if(!this.isOverGUINode) {
+            console.log('unclicked');
+            this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+        }
+        
+        this._mouseStartPointX = evt.clientX;
+        this._mouseStartPointY = evt.clientY;        
+    }
+
+    onUp(evt: React.PointerEvent) {
+        this._mouseStartPointX = null;
+        this._mouseStartPointY = null;
+        this._rootContainer.releasePointerCapture(evt.pointerId);   
+        this._oldY = -1; 
+
+        if (this._selectionBox) {
+           this._selectionBox.parentElement!.removeChild(this._selectionBox);
+           this._selectionBox = null;
+        }
+
+        if (this._frameCandidate) {            
+
+
+            this._frameCandidate.parentElement!.removeChild(this._frameCandidate);
+            this._frameCandidate = null;
+
+        }
+    }
+
+    onWheel(evt: React.WheelEvent) {
+        let delta = evt.deltaY < 0 ? 0.1 : -0.1;
+
+        let oldZoom = this.zoom;
+        this.zoom = Math.min(Math.max(this.MinZoom, this.zoom + delta * this.zoom), this.MaxZoom);
+
+        const boundingRect = evt.currentTarget.getBoundingClientRect();
+        const clientWidth = boundingRect.width;
+        const clientHeight = boundingRect.height;
+        const widthDiff = clientWidth * this.zoom - clientWidth * oldZoom;
+        const heightDiff = clientHeight * this.zoom - clientHeight * oldZoom;
+        const clientX = evt.clientX - boundingRect.left;
+        const clientY = evt.clientY - boundingRect.top;
+
+        const xFactor = (clientX - this.x) / oldZoom / clientWidth;
+        const yFactor = (clientY - this.y) / oldZoom / clientHeight;
+
+        this.x = this.x - widthDiff * xFactor;
+        this.y = this.y - heightDiff * yFactor;
+
+        evt.stopPropagation();
+    }
+
+    zoomToFit() {
+        // Get negative offset
+        let minX = 0;
+        let minY = 0;
+        this._guiNodes.forEach(node => {
+
+            if (node.x < minX) {
+                minX = node.x;
+            }
+            if (node.y < minY) {
+                minY = node.y;
+            }
+        });
+        // Restore to 0
+
+        this._guiNodes.forEach(node => {
+            node.x += -minX;
+            node.y += -minY;            
+            node.cleanAccumulation();
+        });
+
+        // Get correct zoom
+        const xFactor = this._rootContainer.clientWidth / this._rootContainer.scrollWidth;
+        const yFactor = this._rootContainer.clientHeight / this._rootContainer.scrollHeight;
+        const zoomFactor = xFactor < yFactor ? xFactor : yFactor;
+        
+
+        this.zoom = zoomFactor;
+        this.x = 0;
+        this.y = 0;
+    }
+
+
+    public createGUICanvas()
+    {
+        // Get the canvas element from the DOM.
+        const canvas = document.getElementById("workbench-canvas") as HTMLCanvasElement;
+
+        // Associate a Babylon Engine to it.
+        const engine = new Engine(canvas);
+        
+        // Create our first scene.
+        var scene = new Scene(engine);
+        scene.clearColor = new Color4(0.2, 0.2, 0.3, 0.1);
+
+        // This creates and positions a free camera (non-mesh)
+        var camera = new FreeCamera("camera1", new Vector3(0, 5, -10), scene);
+
+        // This targets the camera to scene origin
+        camera.setTarget(Vector3.Zero());
+        
+        // This attaches the camera to the canvas
+        //camera.attachControl(true);
+        
+        // GUI
+        this.globalState.guiTexture = AdvancedDynamicTexture.CreateFullscreenUI("UI");
+        scene.getEngine().onCanvasPointerOutObservable.clear();
+        // Watch for browser/canvas resize events
+        window.addEventListener("resize", function () {
+        engine.resize();
+        });
+
+        engine.runRenderLoop(() => {this.updateGUIs(); scene.render()});
+    }
+    
+    updateGUIs()
+    {
+        this._guiNodes.forEach(element => {
+            element.updateVisual();
+            
+        });
+    }
+ 
+    render() {
+ 
+        return <canvas id="workbench-canvas" 
+        onWheel={evt => this.onWheel(evt)}
+        onPointerMove={evt => this.onMove(evt)}
+        onPointerDown={evt =>  this.onDown(evt)}   
+        onPointerUp={evt =>  this.onUp(evt)} 
+        >   
+        <div id="workbench-container">
+            <div id="workbench-canvas-container">  
+            </div>     
+            <div id="frame-container">                        
+            </div>
+            <svg id="workbench-svg-container">
+            </svg>                    
+            <div id="selection-container">                        
+            </div>
+        </div>
+        </canvas>
+    }
+}

+ 452 - 0
guiEditor/src/diagram/workbenchCanvas.scss

@@ -0,0 +1,452 @@
+#workbench-canvas {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+    padding: 0;            
+    font: 14px "acumin-pro";  
+    user-select: none;
+    overflow: hidden;
+    cursor: move;   
+    background-image:
+        linear-gradient(to right, #4F4E4F 1px, transparent 1px),
+        linear-gradient(to bottom, #4F4E4F 1px, transparent 1px);  
+
+    #selection-container {
+        pointer-events: none;
+        
+        .selection-box {
+            z-index: 10;
+            position: absolute;
+            background: rgba(72, 72, 196, 0.5);
+            border: blue solid 2px;
+        }
+    }
+
+    #workbench-container {
+        width: 100%;
+        height: 100%;
+        left: 0;
+        top: 0;
+        transform-origin: left top;
+        display: grid;
+        grid-template-rows: 100%;          
+        grid-template-columns: 100%;          
+
+        #frame-container {
+            overflow: visible;   
+            grid-row: 1;
+            grid-column: 1;
+            position: relative;
+            width: 100%;
+            height: 100%;             
+        }
+
+        .frame-box {
+            position: absolute;
+            background: rgba(72, 72, 72, 0.7);
+            display: grid;
+            grid-template-rows: 40px calc(100% - 40px);
+            grid-template-columns: 100%;            
+            box-sizing: border-box;
+
+            &.collapsed {
+                height: auto !important;
+                width: 200px !important;
+                z-index: 3;
+
+                .frame-box-header {
+                    font-size: 16px;
+                    grid-template-columns: calc(100% - 37px) 30px 7px;  
+                    
+                    .frame-box-header-collapse {
+                        margin-top: -2px;
+                    }
+                    
+                    .frame-box-header-close {
+                        display: none;
+                    }
+                }
+
+                .frame-comments.has-comments{
+                    .frame-comment-span{
+                        white-space: nowrap;
+                        text-overflow: ellipsis;
+                        overflow: hidden;
+                    }
+                }
+            }
+
+            .frame-box-border {                
+                grid-row: 1 / span 2;
+                grid-column: 1;
+                width: 100%;
+                height: 100%;
+                border: transparent solid 4px;
+                pointer-events: none;
+                box-sizing: border-box;
+            }
+
+            .frame-box-header {
+                grid-row: 1;
+                grid-column: 1;
+                background: rgba(72, 72, 72, 1);    
+                color: white;
+                font-size: 24px;
+                text-align: center;
+                display: grid;
+                grid-template-rows: 100%;  
+                grid-template-columns: calc(100% - 74px) 30px 7px 30px 7px;  
+                align-content: center;
+                overflow: hidden;
+
+                .frame-box-header-button {
+                    cursor: pointer;
+                    align-self: center;
+                    transform-origin: 50% 50%;
+                    transform: scale(1);
+                    stroke: transparent;
+                    fill: white;
+                    display: grid;               
+
+                    &.down {
+                        transform: scale(0.90);
+                    }
+                }
+
+                .frame-box-header-collapse {
+                    grid-column: 2;
+                    grid-row: 1;
+                }
+
+                .frame-box-header-close {
+                    grid-column: 4;
+                    grid-row: 1;
+                }
+
+                .frame-box-header-title {
+                    grid-column: 1;
+                    grid-row: 1;
+                    display: grid;
+                    height: 100%;
+                    width: 100%;
+                    align-self: stretch;
+                    align-items: center;
+                    margin-top: -2px;
+                }
+            }
+
+
+            .frame-comments.has-comments{
+                display: grid;
+                grid-row: 2;
+                grid-column: 1;
+                padding: 0 10px;
+                font-style: italic;
+                word-wrap: break-word;
+            }
+
+            &.selected {
+                .frame-box-border {
+                  border-color: white;
+                }
+            }
+
+            .right-handle {
+                grid-area: 1 / 2 / 3 / 2;
+                width: 4px;
+                background-color: transparent;
+                cursor: ew-resize;
+
+                &::after{
+                    content: "";
+                    width: 8px;
+                    position: absolute;
+                    top: 0;
+                    bottom: 0;
+                    margin-left: -4px;
+                    cursor: ew-resize;
+                    
+                }
+
+                &.collapsed {
+                    cursor: pointer;
+                }
+            }
+
+            .top-right-corner-handle{
+                background-color: transparent;
+                height: 4px;
+                z-index: 21;
+                cursor: ne-resize;
+                width: 4px;
+                margin-left: -6px;
+
+                &::after {
+                    background-color: transparent;
+                    cursor: ne-resize;
+                    margin-left: unset;
+                    top: -4px;
+                    height: 10px;
+                    width: 10px;
+                }
+            }
+
+
+            .bottom-right-corner-handle{
+                background-color: transparent;
+                height: 0px;
+                z-index: 21;
+                cursor: nw-resize;
+                grid-area: 4 / 2 / 4 / 2;;
+                margin-left: -2px;
+
+
+                &::after {
+                    background-color: transparent;
+                    height: 10px;
+                    cursor: nw-resize;
+                    top: unset;
+                    bottom: -4px;
+                    width: 10px;               
+                }
+            }
+
+            .left-handle {
+                grid-area: 1 / 1 / 3 / 1;
+                width: 4px;
+                background-color: transparent;
+                cursor: ew-resize;
+
+                &::before{
+                    content: "";
+                    width: 8px;
+                    position: absolute;
+                    top: 0;
+                    bottom: 0;
+                    margin-left: -4px;
+
+                }
+            }
+
+            .top-left-corner-handle{
+                background-color: transparent;
+                height: 4px;
+                z-index: 21;
+                cursor: nw-resize;
+                width: 4px;
+                margin-left: -4px;
+
+                &::before {
+                    background-color: transparent;
+                    cursor: nw-resize;
+                    margin-left: unset;
+                    top: -4px;
+                    height: 10px;
+                    width: 10px;
+                }
+            }
+
+            .bottom-left-corner-handle{
+                background-color: transparent;
+                height: 0px;
+                z-index: 21;
+                cursor: sw-resize;
+                grid-area: 4 / 1 / 4 / 1;
+
+
+                &::before {
+                    background-color: transparent;
+                    height: 10px;
+                    cursor: sw-resize;
+                    top: unset;
+                    bottom: -4px;
+                    width: 10px;               
+                }
+            }
+
+            .top-handle {
+                grid-area: 1 / 1 / 1 / 1;
+                background-color: transparent;
+                height: 4px;
+                cursor: ns-resize;
+
+                &::before{
+                    content: "";
+                    width: 100%;
+                    position: absolute;
+                    top: -4px;
+                    bottom: 100%;
+                    right: 0;
+                    left: 0;
+                    margin-bottom: -8px;
+                    cursor: ns-resize;
+                    height: 8px;
+                }
+            }
+
+            .bottom-handle {
+                grid-area: 3 / 1 / 3 / 1;
+                background-color: transparent;
+                height: 4px;
+                cursor: ns-resize;
+
+                &::after {
+                    content: "";
+                    width: 100%;
+                    position: absolute;
+                    top: 100%;
+                    bottom: 0;
+                    right: 0;
+                    left: 0;
+                    margin-top: -8px;
+                    cursor: ns-resize;
+                    height: 12px;
+                }
+            }
+            
+            &.collapsed{
+                .top-handle, .top-right-corner-handle, .right-handle, .bottom-right-corner-handle, .bottom-handle, .bottom-left-corner-handle, .left-handle, .top-left-corner-handle {
+                    cursor: default;
+                }
+
+                .right-handle, .bottom-handle, .top-right-corner-handle, .bottom-right-corner-handle{
+                    &::after{
+                        cursor: default;
+                    }
+                }
+
+                .left-handle, .top-handle, .top-left-corner-handle, .bottom-left-corner-handle{
+                    &::before{
+                        cursor: default;
+                    }
+                }
+            }
+        }
+
+        #workbench-svg-container {
+            grid-row: 1;
+            grid-column: 1;
+            position: relative;
+            width: 100%;
+            height: 100%;  
+            overflow: visible; 
+            pointer-events: none;
+            z-index: 2;
+            
+            .link {
+                stroke-width: 4px;    
+                &.selected {                    
+                    stroke: white !important;
+                    stroke-dasharray: 10, 2;
+                }       
+
+                &.hidden {
+                    display: none;
+                }
+            }
+
+            .selection-link {
+                pointer-events: all;
+                stroke-width: 16px;
+                opacity: 0;
+                transition: opacity 75ms;
+                stroke: transparent;                        
+                cursor: pointer;
+
+                &.hidden {
+                    display: none;
+                }
+
+                &:hover, &.selected {
+                    stroke: white !important;
+                    opacity: 0.4;
+                }
+            }
+        }
+
+        #workbench-canvas-container {
+            grid-row: 1;
+            grid-column: 1;
+            position: relative;
+            width: 100%;
+            height: 100%;                  
+
+            .visual {
+                z-index: 4;
+                width: 200px;
+                position: absolute;
+                left: 0;
+                top: 0;
+                background: gray;
+                border: 4px solid black;
+                border-radius: 12px;
+                display: grid;
+                grid-template-rows: 30px auto;
+                grid-template-columns: 100%;
+                color: white;
+
+                &.hidden {
+                    display: none;
+                }
+
+                .comments {
+                    position: absolute;
+                    top: -50px;
+                    width: 200px;
+                    height: 45px;
+                    overflow: hidden;                    
+                    font-style: italic;
+                    opacity: 0.8;
+                    display: grid;
+                    align-items: flex-end;
+                    pointer-events: none;
+                }
+
+                .selection-border {                    
+                    grid-row: 1 / span 3;
+                    grid-column: 1;
+                    margin: -4px;
+
+                    transition: border-color 100ms;
+
+                    border: 4px solid black;
+                    border-radius: 12px;
+                }
+
+                &.selected {
+                    .selection-border {  
+                        border-color: white;
+                    }
+                }
+
+                .header {
+                    grid-row: 1;
+                    grid-column: 1;
+                    border: 4px solid black;
+                    border-top-right-radius: 7px;
+                    border-top-left-radius: 7px;
+                    font-size: 16px;
+                    text-align: center;
+                    margin-top: -1px;
+                    margin-left: -1px;
+                    margin-right: -1px;
+                    white-space: nowrap;
+                    text-overflow: ellipsis;
+                    overflow: hidden;
+                    background: black;
+                    color: white;
+
+                    &.constant {
+                        border-color: #464348;
+                        background: #464348;
+                    }
+            
+                    &.inspector {
+                        border-color: #66491b;
+                        background: #66491b;
+                    }
+                }
+            }
+        }
+    }
+}

+ 44 - 0
guiEditor/src/globalState.ts

@@ -0,0 +1,44 @@
+import { Nullable } from "babylonjs/types";
+import { Observable } from "babylonjs/Misc/observable";
+import { LogEntry } from "./components/log/logComponent";
+import { DataStorage } from "babylonjs/Misc/dataStorage";
+import { Color4 } from "babylonjs/Maths/math.color";
+import { GUINode } from "./diagram/guiNode";
+import { WorkbenchComponent } from "./diagram/workbench";
+import { AdvancedDynamicTexture } from "babylonjs-gui/2D/advancedDynamicTexture";
+import { PropertyChangedEvent } from "./sharedUiComponents/propertyChangedEvent";
+
+export class GlobalState {
+    guiTexture: AdvancedDynamicTexture;
+    hostElement: HTMLElement;
+    hostDocument: HTMLDocument;
+    hostWindow: Window;
+    onSelectionChangedObservable = new Observable<Nullable<GUINode>>();
+    onRebuildRequiredObservable = new Observable<void>();
+    onBuiltObservable = new Observable<void>();
+    onResetRequiredObservable = new Observable<void>();
+    onUpdateRequiredObservable = new Observable<void>();
+    onReOrganizedRequiredObservable = new Observable<void>();
+    onLogRequiredObservable = new Observable<LogEntry>();
+    onErrorMessageDialogRequiredObservable = new Observable<string>();
+    onIsLoadingChanged = new Observable<boolean>();
+    onSelectionBoxMoved = new Observable<ClientRect | DOMRect>();
+    onGuiNodeRemovalObservable = new Observable<GUINode>();
+    backgroundColor: Color4;
+    blockKeyboardEvents = false;
+    controlCamera: boolean;
+    workbench: WorkbenchComponent;
+    onPropertyChangedObservable = new Observable<PropertyChangedEvent>();
+    storeEditorData: (serializationObject: any) => void;
+
+    customSave?: { label: string; action: (data: string) => Promise<void> };
+
+    public constructor() {
+        this.controlCamera = DataStorage.ReadBoolean("ControlCamera", true);
+
+        let r = DataStorage.ReadNumber("BackgroundColorR", 0.12549019607843137);
+        let g = DataStorage.ReadNumber("BackgroundColorG", 0.09803921568627451);
+        let b = DataStorage.ReadNumber("BackgroundColorB", 0.25098039215686274);
+        this.backgroundColor = new Color4(r, g, b, 1.0);
+    }
+}

+ 80 - 0
guiEditor/src/guiEditor.ts

@@ -0,0 +1,80 @@
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+import { GlobalState } from "./globalState";
+import { WorkbenchEditor } from "./workbenchEditor";
+import { Popup } from "./sharedUiComponents/lines/popup";
+import { SerializationTools } from "./serializationTools";
+import { Observable } from "babylonjs/Misc/observable";
+/**
+ * Interface used to specify creation options for the gui editor
+ */
+export interface IGUIEditorOptions {
+    hostElement?: HTMLElement;
+    customSave?: { label: string; action: (data: string) => Promise<void> };
+    customLoadObservable?: Observable<any>;
+}
+
+/**
+ * Class used to create a gui editor
+ */
+export class GUIEditor {
+    private static _CurrentState: GlobalState;
+
+    /**
+     * Show the gui editor
+     * @param options defines the options to use to configure the gui editor
+     */
+    public static Show(options: IGUIEditorOptions) {
+        if (this._CurrentState) {
+            var popupWindow = (Popup as any)["gui-editor"];
+            if (popupWindow) {
+                popupWindow.close();
+            }
+        }
+
+        let hostElement = options.hostElement;
+
+        if (!hostElement) {
+            hostElement = Popup.CreatePopup("BABYLON.JS GUI EDITOR", "gui-editor", 1000, 800)!;
+        }
+
+        let globalState = new GlobalState();
+        globalState.hostElement = hostElement;
+        globalState.hostDocument = hostElement.ownerDocument!;
+        globalState.customSave = options.customSave;
+        globalState.hostWindow = hostElement.ownerDocument!.defaultView!;
+
+        const graphEditor = React.createElement(WorkbenchEditor, {
+            globalState: globalState,
+        });
+
+        ReactDOM.render(graphEditor, hostElement);
+
+        // create the middle workbench canvas
+        if (!globalState.guiTexture) {
+            globalState.workbench.createGUICanvas();
+        }
+
+        if (options.customLoadObservable) {
+            options.customLoadObservable.add((data) => {
+                SerializationTools.Deserialize(data, globalState);
+                globalState.onResetRequiredObservable.notifyObservers();
+                globalState.onBuiltObservable.notifyObservers();
+            });
+        }
+
+        this._CurrentState = globalState;
+
+        // Close the popup window when the page is refreshed or scene is disposed
+        var popupWindow = (Popup as any)["gui-editor"];
+        if (popupWindow) {
+            window.onbeforeunload = () => {
+                var popupWindow = (Popup as any)["gui-editor"];
+                if (popupWindow) {
+                    popupWindow.close();
+                }
+            };
+        }
+        window.addEventListener("beforeunload", () => {});
+    }
+}

+ 54 - 0
guiEditor/src/guiNodeTools.ts

@@ -0,0 +1,54 @@
+import { Button } from "babylonjs-gui/2D/controls/button";
+import { Checkbox } from "babylonjs-gui/2D/controls/checkbox";
+import { ColorPicker } from "babylonjs-gui/2D/controls/colorpicker";
+import { Ellipse } from "babylonjs-gui/2D/controls/ellipse";
+import { Line } from "babylonjs-gui/2D/controls/line";
+import { Rectangle } from "babylonjs-gui/2D/controls/rectangle";
+import { Slider } from "babylonjs-gui/2D/controls/sliders/slider";
+import { TextBlock } from "babylonjs-gui/2D/controls/textBlock";
+
+export class GUINodeTools {
+    public static CreateControlFromString (data: string) {
+        //TODO: Add more elements and create default values for certain types.
+        let element;
+        switch (data) {
+            case "Slider":
+                element = new Slider("Slider");
+                break;
+            case "Checkbox":
+                element = new Checkbox("Checkbox");
+                break;
+            case "ColorPicker":
+                element = new ColorPicker("ColorPicker");
+                break;
+            case "Ellipse":
+                element = new Ellipse("Ellipse");
+                break;
+            case "Rectangle":
+                element = new Rectangle("Rectangle");
+                break;
+            case "Line":
+                element = new Line();
+                element.x1 = 10;
+                element.y1 = 10;
+                element.x2 = 100;
+                element.y2 = 100;
+                element.lineWidth = 5;
+                element.dash = [50, 10];
+                return element;
+            case "Text":
+                element = new TextBlock("Textblock");
+                element.text = "My Text";
+                return element;
+            default:
+                element = Button.CreateSimpleButton("Button", "Click Me");
+                break;
+        }
+
+        element.width = "150px";
+        element.height = "40px";
+        element.color = "#FFFFFFFF";
+        element.isPointerBlocker = true;
+        return element;
+    }
+}

+ 1 - 0
guiEditor/src/index.ts

@@ -0,0 +1 @@
+export * from "./guiEditor";

+ 9 - 0
guiEditor/src/legacy/legacy.ts

@@ -0,0 +1,9 @@
+import { GUIEditor } from "../index";
+
+var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : undefined);
+if (typeof globalObject !== "undefined") {
+    (<any>globalObject).BABYLON = (<any>globalObject).BABYLON || {};
+    (<any>globalObject).BABYLON.GuiEditor = GUIEditor;
+}
+
+export * from "../index";

+ 344 - 0
guiEditor/src/main.scss

@@ -0,0 +1,344 @@
+#gui-editor-workbench-root {
+    display: grid;
+    grid-template-rows: calc(100% - 120px) 120px;
+    height: 100%;
+    width: 100%;
+    background: #464646;
+    font: 14px "acumin-pro";   
+}
+
+.wait-screen {
+    display: grid;
+    justify-content: center;
+    align-content: center;
+    height: 100%;
+    width: 100%;
+    background: #464646;
+    opacity: 0.95;
+    color:white;
+    font: 24px "acumin-pro";  
+    position: absolute;
+    top: 0;
+    left: 0; 
+
+    &.hidden {
+        visibility: hidden;
+    }
+}
+
+#leftGrab {
+    grid-row: 1 / span 2;
+    grid-column: 2;
+    cursor: ew-resize;
+}
+
+#rightGrab {
+    grid-row: 1 / span 2;
+    grid-column: 4;
+    cursor: ew-resize;
+}
+
+.diagram-container {
+    grid-row: 1;
+    grid-column: 3;
+    background: #5f5b60;
+    width: 100%;
+    height: 100%;
+
+    .diagram {
+        display: none;
+        width: 100%;
+        height: 100%;
+    }
+}
+
+.right-panel {
+    grid-row: 1 / span 2;
+    grid-column: 5;
+    display: grid;
+    grid-template-rows: 1fr 40px auto 40px;
+    grid-template-columns: 100%;
+    height: 100%;
+    overflow-y: auto;
+
+    #propertyTab {
+        grid-row: 1;
+        grid-column: 1;
+    }        
+    
+    .button {
+        display: grid;
+        justify-content: center;
+        align-content: center;
+        height: auto;
+        width: calc(100% / 7);
+        cursor: pointer;
+
+        &:hover {
+            background: rgb(51, 122, 183);
+            color: white;
+            opacity: 0.8;
+        }
+
+        &.selected {
+            background: rgb(51, 122, 183);
+            color: white;
+        }
+        
+        &.align {
+            justify-content: stretch;
+            text-align: center;
+        }
+    }    
+
+    #preview-mesh-bar {
+        grid-row: 2;
+        grid-column: 1;
+        display: grid;
+        grid-template-columns: auto 1fr 40px 40px 40px;
+        align-items: center;
+        font-size: 18px;
+        background-color: #555555;
+
+        #file-picker {
+            display: none;
+        }
+
+        .listLine {
+            grid-column: 1;
+            height: 40px;
+            display: grid;
+            grid-template-columns: 0px 1fr;  
+    
+            .label {
+                grid-column: 1;
+                display: flex;
+                align-items: center;
+                font-size: 14px;
+            }
+    
+            .options {
+                grid-column: 2;
+                
+                display: flex;
+                align-items: center;   
+                margin-left: 5px;
+    
+                select {
+                    width: 115px;
+                }
+            } 
+        }
+
+        .button{
+            color: #ffffff;
+            width: 40px;
+            height: 40px;
+            transform-origin: 50% 50%;
+            
+            &:active {
+                transform: scale(0.90);
+            }
+
+            &:hover {
+                background: #3f3461;
+            }
+            
+            &.selected {
+                background: #9379e6;
+            } 
+
+            img{
+                height: 40px;
+                width: 100%;
+            }
+        }
+
+
+        #play-button {
+            grid-column: 3;
+        }
+
+        #color-picker-button {
+            grid-column: 4;
+            display: grid;
+            grid-template-columns: 100%;
+            grid-template-rows: 100%;
+
+            img {
+                height: 40px;
+                width: 30px;  
+            }
+            #color-picker-image {                
+                padding-left: 5px;
+                padding-bottom: 38px;
+            }
+
+            #color-picker {
+                transform: scale(0);
+                grid-column: 1;
+                grid-row: 1;
+            }
+
+            #color-picker-label {
+                width: 100%;
+                background: transparent;
+                cursor: pointer;            
+            }
+        }
+
+        #preview-new-window {
+            grid-column: 5;
+        }
+
+        select {
+            background-color: #a3a3a3;
+            color: #333333;
+        }
+    }
+
+    #preview-config-bar {
+        grid-row: 4;
+        grid-column: 1;
+        display: grid;
+        grid-template-columns: 40px 40px 40px 1fr 40px 40px;
+        color: white;
+        align-items: center;
+        font-size: 18px;    
+
+        .button {
+            width: 40px;
+            grid-row: 1;
+            height: 40px;
+            transform-origin: 50% 50%;
+
+            &:hover {
+                background: #3f3461;
+            }
+
+            &.selected {
+                background: #9379e6;
+            } 
+            
+
+            &:active {
+                transform: scale(0.90);
+            }
+
+            img{
+                height: auto;
+                width: 100%;
+            }
+
+            &.back-face {
+                grid-column: 6
+            }
+
+            &.depth-pass {
+                grid-column: 5 / 6
+            }
+
+            &.hemispheric-light{
+                grid-column: 3 / 4
+            }
+            &.direction-light-1{
+                grid-column: 2 / 3
+
+            }
+            &.direction-light-0{
+                grid-column: 1 / 2
+                
+            }
+        }
+    }
+}
+
+.blocker {
+    visibility: hidden;
+    position: absolute;
+    width: calc(100% - 40px);
+    height: 100%;
+    top: 0;
+    left: 0;
+
+    background: rgba(20, 20, 20, 0.95);    
+    font-family: "acumin-pro";
+    color: white;
+    font-size: 24px;
+
+    display: grid;
+    align-content: center;
+    justify-content: center;
+
+    user-select: none;
+
+    padding: 20px;
+    text-align: center;
+}
+
+#log-console {
+    grid-row: 2;
+    grid-column: 3;
+}
+
+.dialog-container {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    background: rgba(0.1, 0.1, 0.1, 0.6);
+    display: grid;
+    font-family: "acumin-pro";
+    top:0;
+
+    .dialog {
+        align-self: center;
+        justify-self: center;
+        min-height: 140px;
+        max-width: 400px;
+        border-radius: 10px;
+        background: white;
+
+        display: grid;
+        grid-template-columns: 100%;
+        grid-template-rows: calc(100% - 50px) 50px;
+
+        .dialog-message {
+            grid-row: 1;
+            grid-column: 1;
+            margin-top: 20px;
+            padding: 10px;
+            font-size: 18px;
+            color: black;
+        }
+
+        .dialog-buttons {
+            grid-row: 2;
+            grid-column: 1;
+            display: grid;
+            grid-template-rows: 100%;
+            grid-template-columns: 100%;
+            color: white;
+
+            .dialog-button-ok {
+                cursor: pointer;
+                justify-self: center;
+                background:green;
+                min-width: 80px;
+                justify-content: center;
+                display: grid;
+                align-content: center;
+                align-self: center;
+                height: 35px;      
+                border-radius: 10px;
+
+                &:hover {
+                    opacity: 0.8;
+                }
+
+                &.error {
+                    background: red;
+                }
+            }
+        }
+    }
+}

+ 26 - 0
guiEditor/src/nodeLocationInfo.ts

@@ -0,0 +1,26 @@
+export interface INodeLocationInfo {
+    blockId: number;
+    x: number;
+    y: number;
+}
+
+export interface IFrameData {
+    x: number;
+    y: number;
+    width: number;
+    height: number;
+    color: number[];
+    name: string;
+    isCollapsed: boolean;
+    blocks: number[];
+    comments: string;
+}
+
+export interface IEditorData {
+    locations: INodeLocationInfo[];
+    x: number;
+    y: number;
+    zoom: number;
+    frames?: IFrameData[];
+    map?: {[key: number]: number};
+}

+ 0 - 0
guiEditor/src/portal.tsx


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff