Browse Source

Merge 'master' of into WebGPU

sebavan 5 years ago
parent
commit
6765dfe363
100 changed files with 346120 additions and 176033 deletions
  1. 3 1
      .gitignore
  2. 10 0
      .gitpod.Dockerfile
  3. 14 0
      .gitpod.yml
  4. 8 0
      .mergify.yml
  5. 67 20
      .vscode/launch.json
  6. 25 1
      .vscode/tasks.json
  7. 1 0
      CNAME.txt
  8. 1 0
      Playground/_redirects
  9. BIN
      Playground/css/img/clear_button.png
  10. 292 94
      Playground/css/index.css
  11. 446 407
      Playground/debug.html
  12. 110 96
      Playground/frame.html
  13. 46 34
      Playground/full.html
  14. 388 363
      Playground/index-local.html
  15. 399 355
      Playground/index.html
  16. 379 336
      Playground/indexStable.html
  17. 352 312
      Playground/indexWebGPU.html
  18. 10 0
      Playground/js/config_versions.js
  19. 13 1
      Playground/js/definitionWorker.js
  20. 86 5
      Playground/js/examples.js
  21. 62 17
      Playground/js/frame.js
  22. 1 1
      Playground/js/index.js
  23. 0 89
      Playground/js/jquery.qrcode.js
  24. 442 284
      Playground/js/main.js
  25. 36 6
      Playground/js/mainWebGPU.js
  26. 172 21
      Playground/js/monacoCreator.js
  27. 0 524
      Playground/js/pbt.js
  28. 0 1237
      Playground/js/qrcode.js
  29. 50 32
      Playground/js/settingsPG.js
  30. 23 26
      Playground/js/utils.js
  31. 1 1
      Playground/js/zipTool.js
  32. 0 3
      Playground/package.json
  33. BIN
      Playground/scenes/Xbot.glb
  34. 86 0
      Playground/templates.json
  35. 0 55
      Playground/test.html
  36. 65 0
      Playground/textures/PBR_PACK_1_texurePackage.json
  37. BIN
      Playground/textures/ParallaxDiffuse.png
  38. BIN
      Playground/textures/ParallaxNormal.png
  39. 177 0
      Playground/textures/TestPack_texurePackage.json
  40. BIN
      Playground/textures/opacity.png
  41. 3 2
      Playground/zipContent/index.html
  42. 2 6
      Tools/Config/config.json
  43. 17 5
      Tools/DevLoader/BabylonLoader.js
  44. 1 0
      Tools/Gulp/helpers/gulp-processShaders.js
  45. 6 0
      Tools/Gulp/helpers/gulp-validateImports.js
  46. 1 1
      Tools/Gulp/tasks/gulpTasks-libraries.js
  47. 30 4
      Tools/Gulp/tasks/gulpTasks-localRun.js
  48. 78 65
      Tools/Gulp/tasks/gulpTasks-viewerLibraries.js
  49. 1 1
      Tools/Publisher/tasks/buildBabylonJSAndDependencies.js
  50. 11 0
      Tools/Publisher/tasks/processEs6Packages.js
  51. 2 2
      Viewer/src/labs/viewerLabs.ts
  52. 1 1
      Viewer/src/model/modelAnimation.ts
  53. 1 1
      Viewer/src/model/viewerModel.ts
  54. 3 1
      Viewer/tests/karma.conf.js
  55. 3 2
      Viewer/tests/validation/karma.conf.js
  56. 1 0
      Viewer/tests/validation/validate.html
  57. BIN
      assets/nme/currentScreenPostProcess.png
  58. 125 0
      azure-pipelines-cd.yml
  59. 12 0
      contributing.md
  60. 40 40
      dist/ammo.js
  61. 23 0
      dist/ammo.wasm.js
  62. BIN
      dist/ammo.wasm.wasm
  63. 48733 35809
      dist/babylon.d.ts
  64. 2 2
      dist/babylon.js
  65. 70074 34735
      dist/babylon.max.js
  66. 1 1
      dist/babylon.max.js.map
  67. 106791 80687
      dist/babylon.module.d.ts
  68. 1 0
      dist/basisTranscoder/basis_transcoder.js
  69. BIN
      dist/basisTranscoder/basis_transcoder.wasm
  70. 80209 0
      dist/documentation.d.ts
  71. 126 0
      dist/glslang/glslang.js
  72. BIN
      dist/glslang/glslang.wasm
  73. 8 0
      dist/gltf2Interface/babylon.glTF2Interface.d.ts
  74. 1 1
      dist/gltf2Interface/package.json
  75. 9338 7904
      dist/gltf_validator.js
  76. 786 297
      dist/gui/babylon.gui.d.ts
  77. 1978 479
      dist/gui/babylon.gui.js
  78. 1 1
      dist/gui/babylon.gui.js.map
  79. 1 1
      dist/gui/babylon.gui.min.js
  80. 1616 616
      dist/gui/babylon.gui.module.d.ts
  81. 2 2
      dist/gui/package.json
  82. 2 1
      dist/gui/readme.md
  83. 11 12
      dist/inspector/babylon.inspector.bundle.js
  84. 18093 9285
      dist/inspector/babylon.inspector.bundle.max.js
  85. 1 1
      dist/inspector/babylon.inspector.bundle.max.js.map
  86. 270 97
      dist/inspector/babylon.inspector.d.ts
  87. 582 207
      dist/inspector/babylon.inspector.module.d.ts
  88. 10 7
      dist/inspector/package.json
  89. 22 0
      dist/libktx.js
  90. BIN
      dist/libktx.wasm
  91. 543 353
      dist/loaders/babylon.glTF1FileLoader.js
  92. 1 1
      dist/loaders/babylon.glTF1FileLoader.js.map
  93. 2 2
      dist/loaders/babylon.glTF1FileLoader.min.js
  94. 1297 458
      dist/loaders/babylon.glTF2FileLoader.js
  95. 1 1
      dist/loaders/babylon.glTF2FileLoader.js.map
  96. 1 1
      dist/loaders/babylon.glTF2FileLoader.min.js
  97. 1487 617
      dist/loaders/babylon.glTFFileLoader.js
  98. 1 1
      dist/loaders/babylon.glTFFileLoader.js.map
  99. 2 2
      dist/loaders/babylon.glTFFileLoader.min.js
  100. 0 0
      dist/loaders/babylon.objFileLoader.js

+ 3 - 1
.gitignore

@@ -199,4 +199,6 @@ gui/dist/
 /Viewer/tests/tsc
 /Viewer/tests/tsc.cmd
 /Viewer/tests/tsserver
-/Viewer/tests/tsserver.cmd
+/Viewer/tests/tsserver.cmd
+# Local Netlify folder
+.netlify

+ 10 - 0
.gitpod.Dockerfile

@@ -0,0 +1,10 @@
+FROM gitpod/workspace-full-vnc
+
+USER gitpod
+
+RUN sudo apt-get update && \
+    sudo apt-get install -yq chromium-browser firefox && \
+    sudo rm -rf /var/lib/apt/lists/*
+
+ENV CHROME_BIN=/usr/bin/chromium-browser
+ENV BROWSER="Chrome_Without_Sandbox"

+ 14 - 0
.gitpod.yml

@@ -0,0 +1,14 @@
+image:
+  file: .gitpod.Dockerfile
+tasks:
+  - command: gp await-port 1338 && sleep 3 && gp preview $(gp url 1338)/sandbox/index-local.html
+  - before: >
+      cd Tools/Gulp &&
+      npm i typescript gulp@4.0.0 -g &&
+      npm install
+    command: npm run start 
+ports:
+  - port: 1338
+    onOpen: ignore
+  - port: 3000
+    onOpen: ignore

+ 8 - 0
.mergify.yml

@@ -0,0 +1,8 @@
+pull_request_rules:
+  - name: Automatic merge
+    conditions:
+      - label=automerge
+      - status-success=CI
+    actions:
+      merge:
+        method: merge

+ 67 - 20
.vscode/launch.json

@@ -13,7 +13,21 @@
             "runtimeArgs": [
                 "--enable-unsafe-es3-apis"
             ]
-        },        
+        },           
+        {
+            "name": "Launch Node Material Editor (Edge)",
+            "type": "edge",
+            "version": "dev",
+            "request": "launch",
+            "url": "http://localhost:1338/nodeEditor/public/index-local.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "preLaunchTask": "run",
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis"
+            ]
+        },      
         {
             "name": "Launch Viewer (Chrome)",
             "type": "chrome",
@@ -54,6 +68,20 @@
             ]
         },
         {
+            "name": "Launch playground (Edge)",
+            "type": "edge",
+            "version": "dev",
+            "request": "launch",
+            "url": "http://localhost:1338/Playground/index-local.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "preLaunchTask": "run",
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis"
+            ]
+        },
+        {
             "name": "Launch playground (Chrome+WebGL 1.0 forced)",
             "type": "chrome",
             "request": "launch",
@@ -67,6 +95,19 @@
             ]
         },
         {
+            "name": "Launch playground (Chrome+SSL+Public address)",
+            "type": "chrome",
+            "request": "launch",
+            "url": "https://localhost:1338/Playground/index-local.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "preLaunchTask": "start-public-ssl",
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--disable-es3-apis"
+            ]
+        },
+        {
             "name": "Launch Materials Library (Chrome)",
             "type": "chrome",
             "request": "launch",
@@ -130,6 +171,20 @@
             "runtimeArgs": [
                 "--enable-unsafe-es3-apis"
             ]
+        },        
+        {
+            "name": "Launch Local Dev (Edge)",
+            "type": "edge",
+            "version": "dev",
+            "request": "launch",
+            "url": "http://localhost:1338/localDev/index.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "preLaunchTask": "run",
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis"
+            ]
         },
         {
             "name": "Launch Local Dev - Worker mode (Chrome)",
@@ -158,20 +213,6 @@
             ]
         },        
         {
-            "name": "Launch Local Dev (Experimental Firefox)",
-            "type": "firefox",
-            "request": "launch",
-            "reAttach": true,
-            "url": "http://localhost:1338/localDev/index.html",
-            "pathMappings": [
-                {
-                    "url": "http://localhost:1338",
-                    "path": "${workspaceFolder}"
-                }
-            ],
-            "preLaunchTask": "run"
-        },
-        {
             "name": "Launch Build Validation (Chrome)",
             "type": "chrome",
             "request": "launch",
@@ -183,14 +224,20 @@
             "runtimeArgs": [
                 "--enable-unsafe-es3-apis"
             ]
-        },
+        },  
         {
-            "name": "Launch Build Validation (Firefox)",
-            "type": "firefox",
+            "name": "Launch Build Validation (Edge)",
+            "type": "edge",
+            "version": "dev",
             "request": "launch",
-            "reAttach": true,
+            "url": "http://localhost:1338/tests/validation/index.html",
             "webRoot": "${workspaceRoot}/",
-            "url": "http://localhost:1338/tests/validation/index.html"
+            "sourceMaps": true,
+            "preLaunchTask": "run",
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis"
+            ]
         },
         {
             "name": "Launch memory checks (Chrome)",

+ 25 - 1
.vscode/tasks.json

@@ -41,7 +41,7 @@
                 "background": {
                     "activeOnStart": true,
                     "beginsPattern": "Starting \\'watchCore\\'",
-                    "endsPattern": "Watching for file changes"
+                    "endsPattern": "changes"
                 }
             }
         },
@@ -69,6 +69,30 @@
                 }
             ],
             "isBackground": true
+        },
+        {
+            "label": "start-public-ssl",
+            "type": "npm",
+            "script": "start-public-ssl",
+            "path": "Tools/Gulp/",
+            "isBackground": true,
+            "problemMatcher": {
+                "owner": "typescript",
+                "fileLocation": "relative",
+                "pattern": {
+                    "regexp": "^([^\\s].*)\\((\\d+|\\,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$",
+                    "file": 1,
+                    "location": 2,
+                    "severity": 3,
+                    "code": 4,
+                    "message": 5
+                },
+                "background": {
+                    "activeOnStart": true,
+                    "beginsPattern": "Starting \\'watchCore\\'",
+                    "endsPattern": "Watching for file changes"
+                }
+            }
         }
     ]
 }

+ 1 - 0
CNAME.txt

@@ -0,0 +1 @@
+babylonjs.com

+ 1 - 0
Playground/_redirects

@@ -0,0 +1 @@
+/pg/*   /index.html   200

BIN
Playground/css/img/clear_button.png


File diff suppressed because it is too large
+ 292 - 94
Playground/css/index.css


+ 446 - 407
Playground/debug.html

@@ -1,462 +1,501 @@
 <!DOCTYPE html>
 <html>
 
-<!--
-    The purpose of the Debug.html file is to debug a new Playground feature.
-    // TO DO - Fix the console error : "Manifest: Line: 1, column 1, Unexpected token"
- -->
-
-<head>
-    <title>Babylon.js Playground</title>
-    <meta charset='utf-8' />
-    <meta name="viewport" content="width=device-width, user-scalable=no">
-    <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
-
-    <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
-    <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
-    <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
-    <link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
-    <link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
-    <link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
-    <link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
-    <link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
-    <link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
-    <link rel="icon" type="image/png" sizes="192x192"
-        href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
-    <link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
-    <link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
-    <link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
-
-    <meta name="msapplication-TileColor" content="#ffffff">
-    <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-    <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-    <meta name="theme-color" content="#ffffff">
-
-    <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css" />
-    <link rel="stylesheet" href="css/index.css" />
-    <link rel="stylesheet" href="css/index_mobile.css" />
-
-    <!-- Pep -->
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <!-- For canvas/code separator -->
-    <script src="js/libs/split.js"></script>
-
-    <!-- DatGUI CDN -->
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-    <!-- jszip -->
-    <script src="js/libs/jszip.min.js"></script>
-    <script src="js/libs/fileSaver.js"></script>
-
-    <!-- Dependencies -->
-    <script src="https://preview.babylonjs.com/ammo.js"></script>
-    <script src="https://preview.babylonjs.com/recast.js"></script>
-    <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/Oimo.js"></script>
-    <script src="https://preview.babylonjs.com/babylon.max.js"></script>
-    <script src="https://preview.babylonjs.com/gui/babylon.gui.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>
-    <!-- Babylon.js -->
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.fireMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
-
-    <script
-        src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js"></script>
-    <script
-        src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js"></script>
-    <script
-        src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js"></script>
-    <script
-        src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js"></script>
-    <script
-        src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
-
-
-
-    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.js"></script>
-
-    <!-- Monaco -->
-    <script src="node_modules/monaco-editor/dev/vs/loader.js"></script>
-
-    <!-- Extensions -->
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
-</head>
-
-<body>
-    <!-- Big screens -->
-    <div class="navbar navBar1280 languageJS">
-        <div class="categoryTitle">
-            <img class="logo" src="css/img/logo_v4.svg">
-            <div class="version">Playground <span class="versionSub" id="mainTitle1280"></span></div>
-        </div>
+    <head>
+        <title>Babylon.js Playground</title>
+        <meta charset='utf-8' />
+        <meta name="viewport" content="width=device-width, user-scalable=no">
+        <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
+        <meta name="description" content="Babylon.js playground online debug">
+        <meta name="keywords" content="Babylon.js,WebGL,3D, debug">
+
+        <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
+        <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
+        <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
+        <link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
+        <link rel="apple-touch-icon" sizes="114x114"
+            href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
+        <link rel="apple-touch-icon" sizes="120x120"
+            href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
+        <link rel="apple-touch-icon" sizes="144x144"
+            href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
+        <link rel="apple-touch-icon" sizes="152x152"
+            href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
+        <link rel="apple-touch-icon" sizes="180x180"
+            href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
+        <link rel="icon" type="image/png" sizes="192x192"
+            href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
+        <link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
+        <link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
+        <link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
+
+        <meta name="msapplication-TileColor" content="#ffffff">
+        <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
+        <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
+        <meta name="theme-color" content="#ffffff">
+
+        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" />
+        <link rel="stylesheet" href="/css/index.css" />
+        <link rel="stylesheet" href="/css/index_mobile.css" />
+
+        <!-- Pep -->
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+        <!-- For canvas/code separator -->
+        <script src="/js/libs/split.js"></script>
+
+        <!-- DatGUI CDN -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <!-- jszip -->
+        <script src="/js/libs/jszip.min.js"></script>
+        <script src="/js/libs/fileSaver.js"></script>
+
+        <!-- Dependencies -->
+        <script src="https://preview.babylonjs.com/ammo.js"></script>
+        <script src="https://preview.babylonjs.com/recast.js"></script>
+        <script src="https://preview.babylonjs.com/cannon.js"></script>
+        <script src="https://preview.babylonjs.com/Oimo.js"></script>
+        <script src="https://preview.babylonjs.com/libktx.js"></script>
+        <script src="https://preview.babylonjs.com/babylon.max.js"></script>
+        <script src="https://preview.babylonjs.com/gui/babylon.gui.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>
+        <!-- Babylon.js -->
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.fireMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js">
+        </script>
+
+        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
+        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
+
+        <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.js"></script>
+
+        <!-- Extensions -->
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/f43ab677b4bca0a6ab77132d3f785be300382760/ClonerSystem/src/babylonx.cloner.js"
+            async>
+        </script>
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/785013ec55b210d12263c91f3f0a2ae70cf0bc8a/CompoundShader/src/babylonx.CompoundShader.js"
+            async></script>
+
+        <!-- Scene Manager -->
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.manager.js">
+        </script>
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.navmesh.js">
+        </script>
+
+        <!-- Monaco -->
+        <script src="/node_modules/monaco-editor/dev/vs/loader.js"></script>
+
+    </head>
+
+    <body>
+        <!-- Big screens -->
+        <div class="navbar navBar1280 languageJS">
+            <div class="categoryTitle">
+                <img class="logo" src="/css/img/logo_v4.svg">
+                <div class="version">Playground <span class="versionSub" id="mainTitle1280"></span></div>
+            </div>
 
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonJStoTS languageTS" id="toTSbutton1280">Typescript</div>
-            <div class="buttonJStoTS languageJS" id="toJSbutton1280">Javascript</div>
-            <div class="buttonPG run removeOnDiff" id="runButton1280"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="newButton1280"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280"><img src="css/img/diffButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"><img src="css/img/previousButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"><img src="css/img/nextButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280"><img src="css/img/exitButton.svg"></div>
-            <div class="buttonPG select removeOnDiff" id="menuButton1280"><img src="css/img/optionsButton.svg">
-                <div class="toDisplay languageJS">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub languageJS">
-                            <div class="option selected" id="darkTheme1280">Dark</div>
-                            <div class="option" id="lightTheme1280">Light</div>
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonJStoTS languageTS" id="toTSbutton1280">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1280">JS</div>
+                <div class="buttonPG run removeOnDiff" id="runButton1280"><img src="/css/img/playButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="saveButton1280"><img src="/css/img/saveButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"><img
+                        src="/css/img/downloadButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="newButton1280"><img src="/css/img/newButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280"><img
+                        src="/css/img/clearButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280"><img src="/css/img/diffButton.svg">
+                </div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"><img
+                        src="/css/img/previousButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"><img
+                        src="/css/img/nextButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280"><img
+                        src="/css/img/exitButton.svg"></div>
+                <div class="buttonPG select removeOnDiff" id="menuButton1280"><img src="/css/img/optionsButton.svg">
+                    <div class="toDisplay languageJS">
+                        <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub languageJS">
+                                <div class="option selected" id="darkTheme1280">Dark</div>
+                                <div class="option" id="lightTheme1280">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub displayFontSize languageJS">
-                            <div class="option">12</div>
-                            <div class="option selected">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub displayFontSize languageJS">
+                                <div class="option">12</div>
+                                <div class="option selected">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option noSubSelect" id="safemodeToggle1280">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option checked noSubSelect" id="editorButton1280">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option noSubSelect" id="fullscreenButton1280">Fullscreen</div>
-                    <div class="option noSubSelect" id="editorFullscreenButton1280">Editor Fullscreen</div>
-                    <div class="option noSubSelect" id="formatButton1280">Format code</div>
-                    <div class="option noSubSelect" id="minimapToggle1280">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option subSelect" id="qrCodeHover1280">QR Code Link <i class="fa fa-chevron-right"
-                            aria-hidden="true"></i>
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImage1280">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="safemodeToggle1280">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option checked noSubSelect" id="editorButton1280">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option noSubSelect" id="fullscreenButton1280">Fullscreen</div>
+                        <div class="option noSubSelect" id="editorFullscreenButton1280">Editor Fullscreen</div>
+                        <div class="option noSubSelect" id="formatButton1280">Format code</div>
+                        <div class="option noSubSelect" id="minimapToggle1280">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option subSelect" id="qrCodeHover1280">QR Code Link <i class="fa fa-chevron-right"
+                                aria-hidden="true"></i>
+                            <div class="toDisplaySub qrCodeImage">
+                                <div class="option" id="qrCodeImage1280">[QR Code Image]</div>
+                            </div>
                         </div>
+                        <div class="option uncheck noSubSelect" id="debugButton1280">Inspector</div>
+                        <div class="option nosubselect" id="metadataButton1280">Metadata</div>
                     </div>
-                    <div class="option uncheck noSubSelect" id="debugButton1280">Inspector</div>
-                    <div class="option nosubselect" id="metadataButton1280">Metadata</div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="buttonPG select removeOnDiff">
-                <span id="currentVersion1280"></span>
-                <div class="toDisplay currentVersionDisplay" style="display: none"></div>
+            <div class="category right">
+                <div class="buttonPG select removeOnDiff">
+                    <span id="currentVersion1280"></span>
+                    <div class="toDisplay currentVersionDisplay" style="display: none"></div>
+                </div>
+                <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="/css/img/examplesButton.svg">
+                </div>
             </div>
-            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
-    </div>
 
-    <!-- Mid-size screens -->
-    <div class="navbar navBar1024 languageJS">
-        <div class="categoryTitle">
-            <img class="logo" src="css/img/logo_v4.svg">
-            <div class="version"><span class="versionSub" id="mainTitle1024"></span></div>
-        </div>
+        <!-- Mid-size screens -->
+        <div class="navbar navBar1024 languageJS">
+            <div class="categoryTitle">
+                <img class="logo" src="/css/img/logo_v4.svg">
+                <div class="version"><span class="versionSub" id="mainTitle1024"></span></div>
+            </div>
 
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
-            <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
-            <div class="buttonSpaceKiller"></div>
-            <div class="buttonPG run removeOnDiff" id="runButton1024"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="newButton1024"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024"><img src="css/img/diffButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img src="css/img/previousButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img src="css/img/nextButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img src="css/img/exitButton.svg"></div>
-
-            <div class="buttonPG select removeOnDiff" id="menuButton1024"><img src="css/img/optionsButton.svg">
-                <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-
-                        <div class="toDisplaySub">
-                            <div class="option selected" id="darkTheme1024">Dark</div>
-                            <div class="option" id="lightTheme1024">Light</div>
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
+                <div class="buttonSpaceKiller"></div>
+                <div class="buttonPG run removeOnDiff" id="runButton1024"><img src="/css/img/playButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="saveButton1024"><img src="/css/img/saveButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"><img
+                        src="/css/img/downloadButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="newButton1024"><img src="/css/img/newButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024"><img
+                        src="/css/img/clearButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024"><img src="/css/img/diffButton.svg">
+                </div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img
+                        src="/css/img/previousButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img
+                        src="/css/img/nextButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img
+                        src="/css/img/exitButton.svg"></div>
+
+                <div class="buttonPG select removeOnDiff" id="menuButton1024"><img src="/css/img/optionsButton.svg">
+                    <div class="toDisplay">
+                        <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+
+                            <div class="toDisplaySub">
+                                <div class="option selected" id="darkTheme1024">Dark</div>
+                                <div class="option" id="lightTheme1024">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub displayFontSize">
-                            <div class="option">12</div>
-                            <div class="option selected">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub displayFontSize">
+                                <div class="option">12</div>
+                                <div class="option selected">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option noSubSelect" id="safemodeToggle1024">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option checked noSubSelect" id="editorButton1024">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option noSubSelect" id="fullscreenButton1024">Fullscreen</div>
-                    <div class="option noSubSelect" id="editorFullscreenButton1024">Editor Fullscreen</div>
-                    <div class="option noSubSelect" id="formatButton1024">Format code</div>
-                    <div class="option noSubSelect" id="minimapToggle1024">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option subSelect" id="qrCodeHover1024">QR Code Link <i class="fa fa-chevron-right"
-                            aria-hidden="true"></i>
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImage1024">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="safemodeToggle1024">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
                         </div>
+                        <div class="option checked noSubSelect" id="editorButton1024">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option noSubSelect" id="fullscreenButton1024">Fullscreen</div>
+                        <div class="option noSubSelect" id="editorFullscreenButton1024">Editor Fullscreen</div>
+                        <div class="option noSubSelect" id="formatButton1024">Format code</div>
+                        <div class="option noSubSelect" id="minimapToggle1024">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option subSelect" id="qrCodeHover1024">QR Code Link <i class="fa fa-chevron-right"
+                                aria-hidden="true"></i>
+                            <div class="toDisplaySub qrCodeImage">
+                                <div class="option" id="qrCodeImage1024">[QR Code Image]</div>
+                            </div>
+                        </div>
+                        <div class="option uncheck noSubSelect" id="debugButton1024">Inspector</div>
+                        <div class="option noSubSelect" id="metadataButton1024">Metadata</div>
                     </div>
-                    <div class="option uncheck noSubSelect" id="debugButton1024">Inspector</div>
-                    <div class="option noSubSelect" id="metadataButton1024">Metadata</div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="buttonPG select removeOnDiff">
-                <span id="currentVersion1024"></span>
-                <div class="toDisplay currentVersionDisplay" style="display: none">
+            <div class="category right">
+                <div class="buttonPG select removeOnDiff">
+                    <span id="currentVersion1024"></span>
+                    <div class="toDisplay currentVersionDisplay" style="display: none">
+                    </div>
+                </div>
+                <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="/css/img/examplesButton.svg">
                 </div>
             </div>
-            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
-    </div>
-
-    <!-- Mobile -->
-    <div class="navbar navBarMobile languageJS">
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonPG select" id="menuButtonMobile"><img src="css/img/hamburgerButton.svg">
-                <div class="toDisplay">
-                    <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
-                    <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
-                    <div class="option noSubSelect run removeOnDiff" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
-                    <div class="option noSubSelect removeOnDiff" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
-                    <div class="option noSubSelect removeOnDiff" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download</div>
-                    <div class="option noSubSelect removeOnDiff" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
-                    <div class="option noSubSelect removeOnDiff" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear</div>
-                    <div class="option noSubSelect removeOnDiff" id="diffButtonMobile"><img src="css/img/DiffButton.svg">Diff</div>
-                    <div class="option noSubSelect displayOnDiff" id="previousButtonMobile"><img src="css/img/previousButton.svg">Previous</div>
-                    <div class="option noSubSelect displayOnDiff" id="nextButtonMobile"><img src="css/img/nextButton.svg">Next</div>
-                    <div class="option noSubSelect displayOnDiff" id="exitButtonMobile"><img src="css/img/exitButton.svg">Exit</div>
-
-                    <div class="option noSubSelect removeOnDiff" id="debugButtonMobile"><img
-                            src="css/img/inspectorButton.svg">Inspector</div>
-                    <div class="option subSelect removeOnDiff">
-                        <img src="css/img/optionsButton.svg">
-                        <div id="currentVersionMobile"></div>
-                        <div class="toDisplaySub currentVersionDisplay">
+
+        <!-- Mobile -->
+        <div class="navbar navBarMobile languageJS">
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonPG select" id="menuButtonMobile"><img src="/css/img/hamburgerButton.svg">
+                    <div class="toDisplay">
+                        <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
+                        <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
+                        <div class="option noSubSelect run removeOnDiff" id="runButtonMobile"><img
+                                src="/css/img/playButton.svg">Run</div>
+                        <div class="option noSubSelect removeOnDiff" id="saveButtonMobile"><img
+                                src="/css/img/saveButton.svg">Save</div>
+                        <div class="option noSubSelect removeOnDiff" id="zipButtonMobile"><img
+                                src="/css/img/downloadButton.svg">Download</div>
+                        <div class="option noSubSelect removeOnDiff" id="newButtonMobile"><img
+                                src="/css/img/newButton.svg">New</div>
+                        <div class="option noSubSelect removeOnDiff" id="clearButtonMobile"><img
+                                src="/css/img/clearButton.svg">Clear</div>
+                        <div class="option noSubSelect removeOnDiff" id="diffButtonMobile"><img
+                                src="/css/img/DiffButton.svg">Diff</div>
+                        <div class="option noSubSelect displayOnDiff" id="previousButtonMobile"><img
+                                src="/css/img/previousButton.svg">Previous</div>
+                        <div class="option noSubSelect displayOnDiff" id="nextButtonMobile"><img
+                                src="/css/img/nextButton.svg">Next</div>
+                        <div class="option noSubSelect displayOnDiff" id="exitButtonMobile"><img
+                                src="/css/img/exitButton.svg">Exit</div>
+
+                        <div class="option noSubSelect removeOnDiff" id="debugButtonMobile"><img
+                                src="/css/img/inspectorButton.svg">Inspector</div>
+                        <div class="option subSelect removeOnDiff">
+                            <img src="/css/img/optionsButton.svg">
+                            <div id="currentVersionMobile"></div>
+                            <div class="toDisplaySub currentVersionDisplay">
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Theme
-                        <div class="toDisplaySub">
-                            <div class="option selected" id="darkThemeMobile">Dark</div>
-                            <div class="option" id="lightThemeMobile">Light</div>
+                        <div class="option subSelect removeOnDiff"><img src="/css/img/optionsButton.svg">Theme
+                            <div class="toDisplaySub">
+                                <div class="option selected" id="darkThemeMobile">Dark</div>
+                                <div class="option" id="lightThemeMobile">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Font size
-                        <div class="toDisplaySub displayFontSize">
-                            <div class="option">8</div>
-                            <div class="option">10</div>
-                            <div class="option selected">12</div>
-                            <div class="option">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect removeOnDiff"><img src="/css/img/optionsButton.svg">Font size
+                            <div class="toDisplaySub displayFontSize">
+                                <div class="option">8</div>
+                                <div class="option">10</div>
+                                <div class="option selected">12</div>
+                                <div class="option">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div style="display: none;" class="option noSubSelect" id="safemodeToggleMobile">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div style="display: none;" class="option checked noSubSelect" id="editorButtonMobile">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div style="display: none;" class="option nosubselect" id="fullscreenButtonMobile"
-                        style="display: none">Fullscreen</div>
-                    <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
-                        style="display: none">Editor
-                        Fullscreen</div>
-                    <div class="option nosubselect removeOnDiff" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
-                        code</div>
-                    <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <!-- <div class="option subSelect" id="qrCodeHoverMobile"><img src="css/img/optionsButton.svg">QR Code Link
+                        <div style="display: none;" class="option noSubSelect" id="safemodeToggleMobile">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div style="display: none;" class="option checked noSubSelect" id="editorButtonMobile">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div style="display: none;" class="option nosubselect" id="fullscreenButtonMobile"
+                            style="display: none">Fullscreen</div>
+                        <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
+                            style="display: none">Editor
+                            Fullscreen</div>
+                        <div class="option nosubselect removeOnDiff" id="formatButtonMobile"><img
+                                src="/css/img/optionsButton.svg">Format
+                            code</div>
+                        <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <!-- <div class="option subSelect" id="qrCodeHoverMobile"><img src="/css/img/optionsButton.svg">QR Code Link
                         <div class="toDisplaySub qrCodeImage">
                             <div class="option" id="qrCodeImageMobile">[QR Code Image]</div>
                         </div>
                     </div> -->
-                    <div class="option nosubselect removeOnDiff" id="metadataButtonMobile"><img
-                            src="css/img/metadataButton.svg">Metadata</div>
-                    <div class="option nosubselect removeOnDiff"><img class="examplesButton"
-                            src="css/img/examplesButton.svg">Examples</div>
-                    <div class="option subSelect removeOnDiff"><img src="css/img/examplesButton.svg">Links / Tools
-                        <div class="toDisplaySub displayFooterLinks">
-                            <div class="option link">
-                                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                        <div class="option nosubselect removeOnDiff" id="metadataButtonMobile"><img
+                                src="/css/img/metadataButton.svg">Metadata</div>
+                        <div class="option nosubselect removeOnDiff"><img class="examplesButton"
+                                src="/css/img/examplesButton.svg">Examples</div>
+                        <div class="option subSelect removeOnDiff"><img src="/css/img/examplesButton.svg">Links / Tools
+                            <div class="toDisplaySub displayFooterLinks">
+                                <div class="option link">
+                                    <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                                </div>
                             </div>
                         </div>
                     </div>
                 </div>
+                <div class="categoryTitle">
+                    <img class="logo" src="/css/img/logo_v4.svg">
+                    <div class="version"><span class="versionSub" id="mainTitleMobile"></span></div>
+                </div>
             </div>
-            <div class="categoryTitle">
-                <img class="logo" src="css/img/logo_v4.svg">
-                <div class="version"><span class="versionSub" id="mainTitleMobile"></span></div>
-            </div>
-        </div>
 
-        <div id="switchWrapper" class="languageJS removeOnDiff">
-            <img id="switchWrapperCode" src="css/img/codeButton.svg">
-            <img id="switchWrapperCanvas" src="css/img/canvas3Dbutton.svg">
+            <div id="switchWrapper" class="languageJS removeOnDiff">
+                <img id="switchWrapperCode" src="/css/img/codeButton.svg">
+                <img id="switchWrapperCanvas" src="/css/img/canvas3Dbutton.svg">
+            </div>
         </div>
-    </div>
 
-    <!-- Common things -->
+        <!-- Common things -->
 
-    <div class="wrapper">
-        <div id="jsEditor"></div>
-        <div id="diffView" class="diff-view"></div>
-        <div id="canvasZone">
-            <canvas touch-action="none" id="renderCanvas"></canvas>
-        </div>
-    </div>
-    <div id="exampleList" class="javascript">
-        <div id="exampleBanner" class="languageJS">
-            <h1>Examples<img id="examplesButtonClose" src="css/img/clearButton.svg"></h1>
-        </div>
-        <div class="horizontalSeparator"></div>
-        <input id="filterBar" type="text" placeholder="Filter examples...">
-        <img id="filterBarClear"
-            src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
-    </div>
-
-    <div class="fpsLabel languageJS" id="fpsLabel"></div>
-
-    <div id="errorZone">
-    </div>
-
-    <div class="navbarBottom">
-        <div id="statusBar"></div>
-        <div class="links">
-            <div class='link'>
-                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+        <div class="wrapper">
+            <div id="jsEditor"></div>
+            <div id="diffView" class="diff-view"></div>
+            <div id="canvasZone">
+                <canvas touch-action="none" id="renderCanvas"></canvas>
             </div>
-            <div class='link'>
-                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+        </div>
+        <div id="exampleList" class="javascript">
+            <div id="exampleBanner" class="languageJS">
+                <h1>Examples<img id="examplesButtonClose" src="/css/img/clearButton.svg"></h1>
             </div>
+            <div class="horizontalSeparator"></div>
+            <input id="filterBar" type="text" placeholder="Filter examples...">
+            <img id="filterBarClear"
+                src="/css/img/clear_button.png">
+        </div>
+
+        <div class="fpsLabel languageJS" id="fpsLabel"></div>
+
+        <div id="errorZone">
         </div>
-    </div>
-
-    <div id="saveLayer" class="save-layer">
-        <div class="save-form languageJS ">
-            <img id="saveFormButtonClose" src="css/img/clearButton.svg">
-            <label for="saveFormTitle">TITLE</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
-
-            <label for="saveFormDescription">DESCRIPTION</label>
-            <div class="separator"></div>
-            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
-
-            <label for="saveFormTags">TAGS (separated by comma)</label>
-            <div class="separator"></div>
-            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
-
-            <div class="save-form-buttons" id="saveFormButtons">
-                <div id="saveFormButtonOk">OK</div>
-                <div id="saveFormButtonCancel">Cancel</div>
+
+        <div class="navbarBottom">
+            <div id="statusBar"></div>
+            <div class="links">
+                <div class='link'>
+                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div id="diffLayer" class="save-layer">
-        <div class="save-form diff-form">
-            <label for="diffFormSource">COMPARISON SOURCE</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="diffFormSource" placeholder="leave blank to use current snippet, or use snippet ID" class="save-form-title">
+        <div id="saveLayer" class="save-layer">
+            <div class="save-form languageJS ">
+                <img id="saveFormButtonClose" src="/css/img/clearButton.svg">
+                <label for="saveFormTitle">TITLE</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+
+                <label for="saveFormDescription">DESCRIPTION</label>
+                <div class="separator"></div>
+                <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
 
-            <label for="diffFormCompareTo">COMPARE TO</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="diffFormCompareTo" placeholder="snippet ID" class="save-form-title">
+                <label for="saveFormTags">TAGS (separated by comma)</label>
+                <div class="separator"></div>
+                <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+
+                <div class="save-form-buttons" id="saveFormButtons">
+                    <div id="saveFormButtonOk">OK</div>
+                    <div id="saveFormButtonCancel">Cancel</div>
+                </div>
+            </div>
+        </div>
 
-            <div class="save-form-buttons" id="diffFormButtons">
-                <div id="diffFormButtonOk">OK</div>
-                <div id="diffFormButtonCancel">Cancel</div>
+        <div id="diffLayer" class="save-layer">
+            <div class="save-form diff-form">
+                <label for="diffFormSource">COMPARISON SOURCE</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="diffFormSource"
+                    placeholder="leave blank to use current snippet, or use snippet ID" class="save-form-title">
+
+                <label for="diffFormCompareTo">COMPARE TO</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="diffFormCompareTo" placeholder="snippet ID"
+                    class="save-form-title">
+
+                <div class="save-form-buttons" id="diffFormButtons">
+                    <div id="diffFormButtonOk">OK</div>
+                    <div id="diffFormButtonCancel">Cancel</div>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div id="waitDiv">
-        <div id="logo-part">
-            <img src="css/img/v4.svg" id="waitLogo" />
-            <img src="css/img/spinner.svg" id="waitSpinner" />
+        <div id="waitDiv">
+            <div id="logo-part">
+                <img src="/css/img/v4.svg" id="waitLogo" />
+                <img src="/css/img/spinner.svg" id="waitSpinner" />
+            </div>
         </div>
-    </div>
-
-    <!-- jQuery -->
-    <script src="js/libs/jquery.min.js"></script>
-    <script src="js/jquery.qrcode.js"></script>
-    <script src="js/qrcode.js"></script>
-
-    <!-- Main scripts -->
-    <script src="js/config_versions.js"></script>
-    <script src="js/pbt.js"></script>
-    <script src="js/examples.js"></script>
-    <script src="js/main.js"></script>
-    <script src="js/menuPG.js"></script>
-    <script src="js/monacoCreator.js"></script>
-    <script src="js/settingsPG.js"></script>
-    <script src="js/utils.js"></script>
-    <script src="js/zipTool.js"></script>
-    <script src="js/index.js"></script>
-</body>
+
+        <!-- jQuery -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+        <script src="https://rawcdn.githack.com/jeromeetienne/jquery-qrcode/master/jquery.qrcode.min.js"></script>
+
+        <!-- Main scripts -->
+        <script src="/js/config_versions.js"></script>
+        <script src="/js/examples.js"></script>
+        <script src="/js/main.js"></script>
+        <script src="/js/menuPG.js"></script>
+        <script src="/js/monacoCreator.js"></script>
+        <script src="/js/settingsPG.js"></script>
+        <script src="/js/utils.js"></script>
+        <script src="/js/zipTool.js"></script>
+        <script src="/js/index.js"></script>
+    </body>
 
 </html>

+ 110 - 96
Playground/frame.html

@@ -1,103 +1,117 @@
 <!DOCTYPE html>
 <html>
+    <head>
+        <title>Babylon.js Playground</title>
+        <meta charset='utf-8' />
+        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
+        <meta name="description" content="Babylon.js playground is a live editor for Babylon.js WebGL 3D scenes">
+        <meta name="keywords" content="Babylon.js,WebGL,3D">
+        <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
 
-<!--
-    The purpose of the Frame.html file is to ???
-    // TO DO - Complete that
- -->
-
-<head>
-    <title>Babylon.js Playground</title>
-    <meta charset='utf-8' />
-    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
-    <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
-
-    <meta name="msapplication-TileColor" content="#ffffff">
-    <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-    <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-    <meta name="theme-color" content="#ffffff">
-
-    <!-- Pep -->
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-
-    <!-- DatGUI CDN -->
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-
-    <!-- Dependencies -->
-    <script src="https://preview.babylonjs.com/ammo.js"></script>
-    <script src="https://preview.babylonjs.com/recast.js"></script>
-    <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/Oimo.js"></script>
-    <script src="https://preview.babylonjs.com/earcut.min.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/inspector/babylon.inspector.bundle.js"></script>
-    <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js"></script>
-    <!-- Babylon.js -->
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.fireMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
-
-    <script
-        src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js"></script>
-    <script
-        src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js"></script>
-    <script
-        src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js"></script>
-    <script
-        src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js"></script>
-    <script
-        src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
-
-    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
-
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
-    
-    <link rel="stylesheet" href="css/frame.css" />
-</head>
-
-<body>
-    <canvas touch-action="none" id="renderCanvas" tabindex="1"></canvas>
-
-    <div class="footer">
-        <span id="fpsLabel">FPS</span>
-        <div class="footerRight">
-            <a href="javascript:void(null);">
-                <img id="refresh" src="textures/icons/refresh.png" width="36" height="36" alt="Reload page"
-                    title="Reload page" />
-            </a>
-            <a id="edit" href="#" target="_blank">
-                <img src="textures/icons/edit.png" width="36" height="36" alt="Edit in playground"
-                    title="Edit in playground" />
-            </a>
+        <meta name="msapplication-TileColor" content="#ffffff">
+        <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
+        <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
+        <meta name="theme-color" content="#ffffff">
+
+        <!-- Pep -->
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+
+        <!-- DatGUI CDN -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+
+        <!-- Dependencies -->
+        <script src="https://preview.babylonjs.com/ammo.js"></script>
+        <script src="https://preview.babylonjs.com/recast.js"></script>
+        <script src="https://preview.babylonjs.com/cannon.js"></script>
+        <script src="https://preview.babylonjs.com/Oimo.js"></script>
+        <script src="https://preview.babylonjs.com/libktx.js"></script>
+        <script src="https://preview.babylonjs.com/earcut.min.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/inspector/babylon.inspector.bundle.js"></script>
+        <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js"></script>
+        <!-- Babylon.js -->
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.fireMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js">
+        </script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js">
+        </script>
+
+        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
+        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
+
+        <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
+
+        <!-- Extensions -->
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/f43ab677b4bca0a6ab77132d3f785be300382760/ClonerSystem/src/babylonx.cloner.js"
+            async>
+        </script>
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/785013ec55b210d12263c91f3f0a2ae70cf0bc8a/CompoundShader/src/babylonx.CompoundShader.js"
+            async></script>
+
+        <!-- Scene Manager -->
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.manager.js">
+        </script>
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.navmesh.js">
+        </script>
+
+        <link rel="stylesheet" href="/css/frame.css" />
+    </head>
+
+    <body>
+        <canvas touch-action="none" id="renderCanvas" tabindex="1"></canvas>
+
+        <div class="footer">
+            <span id="fpsLabel">FPS</span>
+            <div class="footerRight">
+                <a href="javascript:void(null);">
+                    <img id="refresh" src="/textures/icons/refresh.png" width="36" height="36" alt="Reload page"
+                        title="Reload page" />
+                </a>
+                <a id="edit" href="#" target="_blank">
+                    <img src="/textures/icons/edit.png" width="36" height="36" alt="Edit in playground"
+                        title="Edit in playground" />
+                </a>
+            </div>
         </div>
-    </div>
 
-    <!-- jQuery -->
-    <script src="https://code.jquery.com/jquery.js"></script>
-    
-    <script src="js/frame.js"></script>
-</body>
+        <!-- jQuery -->
+        <script src="https://code.jquery.com/jquery.min.js"></script>
+
+        <script src="/js/frame.js"></script>
+    </body>
 
 </html>

+ 46 - 34
Playground/full.html

@@ -1,43 +1,55 @@
 <!DOCTYPE html>
 <html>
 
-<head>
-    <title>Babylon.js Playground</title>
-    <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
-    <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
-    <meta name="msapplication-TileColor" content="#ffffff">
-    <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-    <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-    <meta name="theme-color" content="#ffffff">
-    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
+    <head>
+        <title>Babylon.js Playground</title>
+        <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
+        <meta name="theme-color" content="#ffffff">
+        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
 
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <!-- Babylon.js -->
-    <script src="https://preview.babylonjs.com/ammo.js"></script>
-    <script src="https://preview.babylonjs.com/recast.js"></script>
-    <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/Oimo.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/inspector/babylon.inspector.bundle.js"></script>
-    <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.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/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+        <!-- DatGUI -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <!-- Babylon.js -->
+        <script src="https://preview.babylonjs.com/ammo.js"></script>
+        <script src="https://preview.babylonjs.com/recast.js"></script>
+        <script src="https://preview.babylonjs.com/cannon.js"></script>
+        <script src="https://preview.babylonjs.com/Oimo.js"></script>
+        <script src="https://preview.babylonjs.com/libktx.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/inspector/babylon.inspector.bundle.js"></script>
+        <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.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/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
 
+        <!-- Extensions -->
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/f43ab677b4bca0a6ab77132d3f785be300382760/ClonerSystem/src/babylonx.cloner.js"
+            async>
+        </script>
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/785013ec55b210d12263c91f3f0a2ae70cf0bc8a/CompoundShader/src/babylonx.CompoundShader.js"
+            async></script>
 
+        <!-- Scene Manager -->
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.manager.js">
+        </script>
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.navmesh.js">
+        </script>
+        <link href="/css/frame.css" rel="stylesheet" />
+    </head>
 
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
-    <link href="css/frame.css" rel="stylesheet" />
-</head>
-
-<body>
-    <!-- Override frame style -->
-    <canvas touch-action="none" id="renderCanvas" tabindex="1" style="height: 100%"></canvas>
-    <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="js/frame.js"></script>
-</body>
+    <body>
+        <!-- Override frame style -->
+        <canvas touch-action="none" id="renderCanvas" tabindex="1" style="height: 100%"></canvas>
+        <script src="https://code.jquery.com/jquery.min.js"></script>
+        <script src="/js/frame.js"></script>
+    </body>
 
 </html>

+ 388 - 363
Playground/index-local.html

@@ -1,418 +1,443 @@
 <!DOCTYPE html>
 <html>
 
-<!--
-    The purpose of the index-local.html file is to ???
-    // TO DO - Complete that
-    // TO DO - Fix error - "BabylonLoader.js:26 GET http://localhost/Tools/Config/config.json 404 (Not Found)". File exist, Wamp can't read it
- -->
-
-<head>
-    <title>Babylon.js Playground</title>
-    <meta charset='utf-8' />
-    <meta name="viewport" content="width=device-width, user-scalable=no">
-    <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
-
-    <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css">
-    <link rel="stylesheet" href="css/index.css" />
-    <link rel="stylesheet" href="css/index_mobile.css" />
-
-    <!-- Pep -->
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <!--For canvas/code separator-->
-    <script src="js/libs/split.js"></script>
-
-    <!-- DatGUI -->
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-    <!-- jszip -->
-    <script src="js/libs/jszip.min.js"></script>
-    <script src="js/libs/fileSaver.js"></script>
-
-    <!-- Dependencies -->
-    <script src="../dist/preview%20release/ammo.js"></script>
-    <script src="../dist/preview%20release/recast.js"></script>
-    <script src="../dist/preview%20release/cannon.js"></script>
-    <script src="../dist/preview%20release/Oimo.js"></script>
-    <script src="../dist/preview%20release/earcut.min.js"></script>
-    <!-- Monaco -->
-
-    <!-- Babylon.js -->
-    <script src="../Tools/DevLoader/BabylonLoader.js"></script>
-</head>
-
-<body>
-    <!-- Big screens -->
-    <div class="navbar navBar1280 languageJS">
-        <div class="categoryTitle">
-            <img class="logo" src="css/img/logo_v4.svg">
-            <div class="version">Playground <span class="versionSub" id="mainTitle1280"></span></div>
-        </div>
+    <head>
+        <title>Babylon.js Playground</title>
+        <meta charset='utf-8' />
+        <meta name="viewport" content="width=device-width, user-scalable=no">
+        <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
+        <meta name="description" content="Babylon.js playground is a live editor for Babylon.js WebGL 3D scenes">
+        <meta name="keywords" content="Babylon.js,WebGL,3D">
+
+        <link rel="stylesheet"
+            href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" />
+        <link rel="stylesheet" href="/css/index.css" />
+        <link rel="stylesheet" href="/css/index_mobile.css" />
+
+        <!-- Pep -->
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+        <!--For canvas/code separator-->
+        <script src="js/libs/split.js"></script>
+
+        <!-- DatGUI -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <!-- jszip -->
+        <script src="js/libs/jszip.min.js"></script>
+        <script src="js/libs/fileSaver.js"></script>
+
+        <!-- Dependencies -->
+        <script src="../dist/preview%20release/ammo.js"></script>
+        <script src="../dist/preview%20release/recast.js"></script>
+        <script src="../dist/preview%20release/cannon.js"></script>
+        <script src="../dist/preview%20release/Oimo.js"></script>
+        <script src="../dist/preview%20release/libktx.js"></script>
+        <script src="../dist/preview%20release/earcut.min.js"></script>
+        <!-- Monaco -->
+
+        <!-- Babylon.js -->
+        <script src="../Tools/DevLoader/BabylonLoader.js"></script>
+    </head>
+
+    <body>
+        <!-- Big screens -->
+        <div class="navbar navBar1280 languageJS">
+            <div class="categoryTitle">
+                <img class="logo" src="css/img/logo_v4.svg">
+                <div class="version">Playground <span class="versionSub" id="mainTitle1280"></span></div>
+            </div>
 
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonJStoTS languageTS" id="toTSbutton1280">Typescript</div>
-            <div class="buttonJStoTS languageJS" id="toJSbutton1280">Javascript</div>
-            <div class="buttonPG run removeOnDiff" id="runButton1280"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="newButton1280"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280"><img src="css/img/diffButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"><img src="css/img/previousButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"><img src="css/img/nextButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280"><img src="css/img/exitButton.svg"></div>
-            <div class="buttonPG select removeOnDiff" id="menuButton1280"><img src="css/img/optionsButton.svg">
-                <div class="toDisplay languageJS">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub languageJS">
-                            <div class="option selected" id="darkTheme1280">Dark</div>
-                            <div class="option" id="lightTheme1280">Light</div>
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonJStoTS languageTS" id="toTSbutton1280" title="Switch to TypeScript">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1280" title="Switch to JavaScript">JS</div>
+                <div class="buttonPG run removeOnDiff" id="runButton1280" title="Run&#10;(Alt+Enter)"><img
+                        src="css/img/playButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="saveButton1280" title="Save&#10;(Ctrl+S)"><img
+                        src="css/img/saveButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"
+                    title="Download ZIP&#10;(Ctrl+Shift+S)"><img src="css/img/downloadButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="newButton1280" title="Create new"><img
+                        src="css/img/newButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280" title="Clear"><img
+                        src="css/img/clearButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280" title="Compare"><img
+                        src="css/img/diffButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"
+                    title="Previous difference&#10;(Shift+Alt+F5)"><img src="css/img/previousButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"
+                    title="Next difference&#10;(Alt+F5)"><img src="css/img/nextButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280" title="Exit&#10;(Esc)"><img
+                        src="css/img/exitButton.svg"></div>
+                <div class="buttonPG select removeOnDiff" id="menuButton1280" title="Options"><img
+                        src="css/img/optionsButton.svg">
+                    <div class="toDisplay languageJS">
+                        <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub languageJS">
+                                <div class="option selected" id="darkTheme1280">Dark</div>
+                                <div class="option" id="lightTheme1280">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub displayFontSize languageJS">
-                            <div class="option">12</div>
-                            <div class="option selected">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub displayFontSize languageJS">
+                                <div class="option">12</div>
+                                <div class="option selected">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option noSubSelect" id="safemodeToggle1280">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option checked noSubSelect" id="editorButton1280">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option noSubSelect" id="fullscreenButton1280">Fullscreen</div>
-                    <div class="option noSubSelect" id="editorFullscreenButton1280">Editor Fullscreen</div>
-                    <div class="option noSubSelect" id="formatButton1280">Format code</div>
-                    <div class="option noSubSelect" id="minimapToggle1280">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option subSelect" id="qrCodeHover1280">QR Code Link <i class="fa fa-chevron-right"
-                            aria-hidden="true"></i>
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImage1280">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="safemodeToggle1280">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option checked noSubSelect" id="editorButton1280">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option noSubSelect" id="fullscreenButton1280">Fullscreen</div>
+                        <div class="option noSubSelect" id="editorFullscreenButton1280">Editor Fullscreen</div>
+                        <div class="option noSubSelect" id="formatButton1280">Format code</div>
+                        <div class="option noSubSelect" id="minimapToggle1280">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
                         </div>
+                        <div class="option subSelect" id="qrCodeHover1280">QR Code Link <i class="fa fa-chevron-right"
+                                aria-hidden="true"></i>
+                            <div class="toDisplaySub qrCodeImage">
+                                <div class="option" id="qrCodeImage1280">[QR Code Image]</div>
+                            </div>
+                        </div>
+                        <div class="option uncheck noSubSelect" id="debugButton1280">Inspector</div>
+                        <div class="option nosubselect" id="metadataButton1280">Metadata</div>
                     </div>
-                    <div class="option uncheck noSubSelect" id="debugButton1280">Inspector</div>
-                    <div class="option nosubselect" id="metadataButton1280">Metadata</div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="buttonPG select removeOnDiff">
-                <span id="currentVersion1280"></span>
-                <div class="toDisplay currentVersionDisplay" style="display: none"></div>
+            <div class="category right">
+                <div class="buttonPG select removeOnDiff" title="Select Babylon.js version">
+                    <span id="currentVersion1280"></span>
+                    <div class="toDisplay currentVersionDisplay" style="display: none"></div>
+                </div>
+                <div class="buttonPG select removeOnDiff" title="Examples"><img class="examplesButton"
+                        src="css/img/examplesButton.svg"></div>
             </div>
-            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
-    </div>
 
-    <!-- Mid-size screens -->
-    <div class="navbar navBar1024 languageJS">
-        <div class="categoryTitle">
-            <img class="logo" src="css/img/logo_v4.svg">
-            <div class="version"><span class="versionSub" id="mainTitle1024"></span></div>
-        </div>
+        <!-- Mid-size screens -->
+        <div class="navbar navBar1024 languageJS">
+            <div class="categoryTitle">
+                <img class="logo" src="css/img/logo_v4.svg">
+                <div class="version"><span class="versionSub" id="mainTitle1024"></span></div>
+            </div>
 
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
-            <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
-            <div class="buttonSpaceKiller"></div>
-            <div class="buttonPG run removeOnDiff" id="runButton1024"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="newButton1024"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024"><img src="css/img/diffButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img src="css/img/previousButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img src="css/img/nextButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img src="css/img/exitButton.svg"></div>
-
-            <div class="buttonPG select removeOnDiff" id="menuButton1024"><img src="css/img/optionsButton.svg">
-                <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-
-                        <div class="toDisplaySub">
-                            <div class="option selected" id="darkTheme1024">Dark</div>
-                            <div class="option" id="lightTheme1024">Light</div>
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonJStoTS languageTS" id="toTSbutton1024" title="Switch to TypeScript">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1024" title="Switch to JavaScript">JS</div>
+                <div class="buttonSpaceKiller"></div>
+                <div class="buttonPG run removeOnDiff" id="runButton1024" title="Run&#10;(Alt+Enter)"><img
+                        src="css/img/playButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="saveButton1024" title="Save&#10;(Ctrl+S)"><img
+                        src="css/img/saveButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"
+                    title="Download ZIP&#10;(Ctrl+Shift+S)"><img src="css/img/downloadButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="newButton1024" title="Create new"><img
+                        src="css/img/newButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024" title="Clear"><img
+                        src="css/img/clearButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024" title="Compare"><img
+                        src="css/img/diffButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img
+                        src="css/img/previousButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img src="css/img/nextButton.svg">
+                </div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img src="css/img/exitButton.svg">
+                </div>
+
+                <div class="buttonPG select removeOnDiff" id="menuButton1024" title="Options"><img
+                        src="css/img/optionsButton.svg">
+                    <div class="toDisplay">
+                        <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+
+                            <div class="toDisplaySub">
+                                <div class="option selected" id="darkTheme1024">Dark</div>
+                                <div class="option" id="lightTheme1024">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub displayFontSize">
-                            <div class="option">12</div>
-                            <div class="option selected">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub displayFontSize">
+                                <div class="option">12</div>
+                                <div class="option selected">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option noSubSelect" id="safemodeToggle1024">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option checked noSubSelect" id="editorButton1024">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option noSubSelect" id="fullscreenButton1024">Fullscreen</div>
-                    <div class="option noSubSelect" id="editorFullscreenButton1024">Editor Fullscreen</div>
-                    <div class="option noSubSelect" id="formatButton1024">Format code</div>
-                    <div class="option noSubSelect" id="minimapToggle1024">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option subSelect" id="qrCodeHover1024">QR Code Link <i class="fa fa-chevron-right"
-                            aria-hidden="true"></i>
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImage1024">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="safemodeToggle1024">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option checked noSubSelect" id="editorButton1024">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option noSubSelect" id="fullscreenButton1024">Fullscreen</div>
+                        <div class="option noSubSelect" id="editorFullscreenButton1024">Editor Fullscreen</div>
+                        <div class="option noSubSelect" id="formatButton1024">Format code</div>
+                        <div class="option noSubSelect" id="minimapToggle1024">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option subSelect" id="qrCodeHover1024">QR Code Link <i class="fa fa-chevron-right"
+                                aria-hidden="true"></i>
+                            <div class="toDisplaySub qrCodeImage">
+                                <div class="option" id="qrCodeImage1024">[QR Code Image]</div>
+                            </div>
                         </div>
+                        <div class="option uncheck noSubSelect" id="debugButton1024">Inspector</div>
+                        <div class="option noSubSelect" id="metadataButton1024">Metadata</div>
                     </div>
-                    <div class="option uncheck noSubSelect" id="debugButton1024">Inspector</div>
-                    <div class="option noSubSelect" id="metadataButton1024">Metadata</div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="buttonPG select removeOnDiff">
-                <span id="currentVersion1024"></span>
-                <div class="toDisplay currentVersionDisplay" style="display: none">
+            <div class="category right">
+                <div class="buttonPG select removeOnDiff" title="Select Babylon.js version">
+                    <span id="currentVersion1024"></span>
+                    <div class="toDisplay currentVersionDisplay" style="display: none">
+                    </div>
                 </div>
+                <div class="buttonPG select removeOnDiff" title="Examples"><img class="examplesButton"
+                        src="css/img/examplesButton.svg"></div>
             </div>
-            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
-    </div>
-
-    <!-- Mobile -->
-    <div class="navbar navBarMobile languageJS">
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonPG select" id="menuButtonMobile"><img src="css/img/hamburgerButton.svg">
-                <div class="toDisplay">
-                    <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
-                    <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
-                    <div class="option noSubSelect run removeOnDiff" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
-                    <div class="option noSubSelect removeOnDiff" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
-                    <div class="option noSubSelect removeOnDiff" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download</div>
-                    <div class="option noSubSelect removeOnDiff" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
-                    <div class="option noSubSelect removeOnDiff" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear</div>
-                    <div class="option noSubSelect removeOnDiff" id="diffButtonMobile"><img src="css/img/DiffButton.svg">Diff</div>
-                    <div class="option noSubSelect displayOnDiff" id="previousButtonMobile"><img src="css/img/previousButton.svg">Previous</div>
-                    <div class="option noSubSelect displayOnDiff" id="nextButtonMobile"><img src="css/img/nextButton.svg">Next</div>
-                    <div class="option noSubSelect displayOnDiff" id="exitButtonMobile"><img src="css/img/exitButton.svg">Exit</div>
-
-                    <div class="option noSubSelect removeOnDiff" id="debugButtonMobile"><img
-                            src="css/img/inspectorButton.svg">Inspector</div>
-                    <div class="option subSelect removeOnDiff">
-                        <img src="css/img/optionsButton.svg">
-                        <div id="currentVersionMobile"></div>
-                        <div class="toDisplaySub currentVersionDisplay">
+
+        <!-- Mobile -->
+        <div class="navbar navBarMobile languageJS">
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonPG select" id="menuButtonMobile"><img src="css/img/hamburgerButton.svg">
+                    <div class="toDisplay">
+                        <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
+                        <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
+                        <div class="option noSubSelect run removeOnDiff" id="runButtonMobile"><img
+                                src="css/img/playButton.svg">Run</div>
+                        <div class="option noSubSelect removeOnDiff" id="saveButtonMobile"><img
+                                src="css/img/saveButton.svg">Save</div>
+                        <div class="option noSubSelect removeOnDiff" id="zipButtonMobile"><img
+                                src="css/img/downloadButton.svg">Download</div>
+                        <div class="option noSubSelect removeOnDiff" id="newButtonMobile"><img
+                                src="css/img/newButton.svg">New</div>
+                        <div class="option noSubSelect removeOnDiff" id="clearButtonMobile"><img
+                                src="css/img/clearButton.svg">Clear</div>
+                        <div class="option noSubSelect removeOnDiff" id="diffButtonMobile"><img
+                                src="css/img/diffButton.svg">Diff</div>
+                        <div class="option noSubSelect displayOnDiff" id="previousButtonMobile"><img
+                                src="css/img/previousButton.svg">Previous</div>
+                        <div class="option noSubSelect displayOnDiff" id="nextButtonMobile"><img
+                                src="css/img/nextButton.svg">Next</div>
+                        <div class="option noSubSelect displayOnDiff" id="exitButtonMobile"><img
+                                src="css/img/exitButton.svg">Exit</div>
+
+                        <div class="option noSubSelect removeOnDiff" id="debugButtonMobile"><img
+                                src="css/img/inspectorButton.svg">Inspector</div>
+                        <div class="option subSelect removeOnDiff">
+                            <img src="css/img/optionsButton.svg">
+                            <div id="currentVersionMobile"></div>
+                            <div class="toDisplaySub currentVersionDisplay">
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Theme
-                        <div class="toDisplaySub">
-                            <div class="option selected" id="darkThemeMobile">Dark</div>
-                            <div class="option" id="lightThemeMobile">Light</div>
+                        <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Theme
+                            <div class="toDisplaySub">
+                                <div class="option selected" id="darkThemeMobile">Dark</div>
+                                <div class="option" id="lightThemeMobile">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Font size
-                        <div class="toDisplaySub displayFontSize">
-                            <div class="option">8</div>
-                            <div class="option">10</div>
-                            <div class="option selected">12</div>
-                            <div class="option">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Font size
+                            <div class="toDisplaySub displayFontSize">
+                                <div class="option">8</div>
+                                <div class="option">10</div>
+                                <div class="option selected">12</div>
+                                <div class="option">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div style="display: none;" class="option noSubSelect" id="safemodeToggleMobile">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div style="display: none;" class="option checked noSubSelect" id="editorButtonMobile">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div style="display: none;" class="option nosubselect" id="fullscreenButtonMobile"
-                        style="display: none">Fullscreen</div>
-                    <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
-                        style="display: none">Editor
-                        Fullscreen</div>
-                    <div class="option nosubselect removeOnDiff" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
-                        code</div>
-                    <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <!-- <div class="option subSelect" id="qrCodeHoverMobile"><img src="css/img/optionsButton.svg">QR Code Link
+                        <div style="display: none;" class="option noSubSelect" id="safemodeToggleMobile">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div style="display: none;" class="option checked noSubSelect" id="editorButtonMobile">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div style="display: none;" class="option nosubselect" id="fullscreenButtonMobile"
+                            style="display: none">Fullscreen</div>
+                        <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
+                            style="display: none">Editor
+                            Fullscreen</div>
+                        <div class="option nosubselect removeOnDiff" id="formatButtonMobile"><img
+                                src="css/img/optionsButton.svg">Format
+                            code</div>
+                        <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <!-- <div class="option subSelect" id="qrCodeHoverMobile"><img src="css/img/optionsButton.svg">QR Code Link
                         <div class="toDisplaySub qrCodeImage">
                             <div class="option" id="qrCodeImageMobile">[QR Code Image]</div>
                         </div>
                     </div> -->
-                    <div class="option nosubselect removeOnDiff" id="metadataButtonMobile"><img
-                            src="css/img/metadataButton.svg">Metadata</div>
-                    <div class="option nosubselect removeOnDiff"><img class="examplesButton"
-                            src="css/img/examplesButton.svg">Examples</div>
-                    <div class="option subSelect removeOnDiff"><img src="css/img/examplesButton.svg">Links / Tools
-                        <div class="toDisplaySub displayFooterLinks">
-                            <div class="option link">
-                                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                        <div class="option nosubselect removeOnDiff" id="metadataButtonMobile"><img
+                                src="css/img/metadataButton.svg">Metadata</div>
+                        <div class="option nosubselect removeOnDiff"><img class="examplesButton"
+                                src="css/img/examplesButton.svg">Examples</div>
+                        <div class="option subSelect removeOnDiff"><img src="css/img/examplesButton.svg">Links / Tools
+                            <div class="toDisplaySub displayFooterLinks">
+                                <div class="option link">
+                                    <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                                </div>
                             </div>
                         </div>
                     </div>
                 </div>
+                <div class="categoryTitle">
+                    <img class="logo" src="css/img/logo_v4.svg">
+                    <div class="version"><span class="versionSub" id="mainTitleMobile"></span></div>
+                </div>
             </div>
-            <div class="categoryTitle">
-                <img class="logo" src="css/img/logo_v4.svg">
-                <div class="version"><span class="versionSub" id="mainTitleMobile"></span></div>
-            </div>
-        </div>
 
-        <div id="switchWrapper" class="languageJS removeOnDiff">
-            <img id="switchWrapperCode" src="css/img/codeButton.svg">
-            <img id="switchWrapperCanvas" src="css/img/canvas3Dbutton.svg">
+            <div id="switchWrapper" class="languageJS removeOnDiff">
+                <img id="switchWrapperCode" src="css/img/codeButton.svg">
+                <img id="switchWrapperCanvas" src="css/img/canvas3Dbutton.svg">
+            </div>
         </div>
-    </div>
 
-    <!-- Common things -->
+        <!-- Common things -->
 
-    <div class="wrapper">
-        <div id="jsEditor"></div>
-        <div id="diffView" class="diff-view"></div>
-        <div id="canvasZone">
-            <canvas touch-action="none" id="renderCanvas"></canvas>
-        </div>
-    </div>
-    <div id="exampleList" class="javascript">
-        <div id="exampleBanner" class="languageJS">
-            <h1>Examples<img id="examplesButtonClose" src="css/img/clearButton.svg"></h1>
-        </div>
-        <div class="horizontalSeparator"></div>
-        <input id="filterBar" type="text" placeholder="Filter examples...">
-        <img id="filterBarClear"
-            src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
-    </div>
-
-    <div class="fpsLabel languageJS" id="fpsLabel"></div>
-
-    <div id="errorZone">
-    </div>
-
-    <div class="navbarBottom">
-        <div id="statusBar"></div>
-        <div class="links">
-            <div class='link'>
-                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+        <div class="wrapper">
+            <div id="jsEditor"></div>
+            <div id="diffView" class="diff-view"></div>
+            <div id="canvasZone">
+                <canvas touch-action="none" id="renderCanvas"></canvas>
             </div>
-            <div class='link'>
-                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+        </div>
+        <div id="exampleList" class="javascript">
+            <div id="exampleBanner" class="languageJS">
+                <h1>Examples<img id="examplesButtonClose" src="css/img/clearButton.svg"></h1>
             </div>
+            <div class="horizontalSeparator"></div>
+            <input id="filterBar" type="text" placeholder="Filter examples...">
+            <img id="filterBarClear"
+                src="css/img/clear_button.png">
         </div>
-    </div>
-
-    <div id="saveLayer" class="save-layer">
-        <div class="save-form languageJS ">
-            <img id="saveFormButtonClose" src="css/img/clearButton.svg">
-            <label for="saveFormTitle">TITLE</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
-
-            <label for="saveFormDescription">DESCRIPTION</label>
-            <div class="separator"></div>
-            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
-
-            <label for="saveFormTags">TAGS (separated by comma)</label>
-            <div class="separator"></div>
-            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
-
-            <div class="save-form-buttons" id="saveFormButtons">
-                <div id="saveFormButtonOk">OK</div>
-                <div id="saveFormButtonCancel">Cancel</div>
+
+        <div class="fpsLabel languageJS" id="fpsLabel"></div>
+
+        <div id="errorZone">
+        </div>
+
+        <div class="navbarBottom">
+            <div id="statusBar"></div>
+            <div class="links">
+                <div class='link'>
+                    <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div id="diffLayer" class="save-layer">
-        <div class="save-form diff-form">
-            <label for="diffFormSource">COMPARISON SOURCE</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="diffFormSource" placeholder="leave blank to use current snippet, or use snippet ID" class="save-form-title">
+        <div id="saveLayer" class="save-layer">
+            <div class="save-form languageJS ">
+                <img id="saveFormButtonClose" src="css/img/clearButton.svg">
+                <label for="saveFormTitle">TITLE</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+
+                <label for="saveFormDescription">DESCRIPTION</label>
+                <div class="separator"></div>
+                <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
 
-            <label for="diffFormCompareTo">COMPARE TO</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="diffFormCompareTo" placeholder="snippet ID" class="save-form-title">
+                <label for="saveFormTags">TAGS (separated by comma)</label>
+                <div class="separator"></div>
+                <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+
+                <div class="save-form-buttons" id="saveFormButtons">
+                    <div id="saveFormButtonOk">OK</div>
+                    <div id="saveFormButtonCancel">Cancel</div>
+                </div>
+            </div>
+        </div>
 
-            <div class="save-form-buttons" id="diffFormButtons">
-                <div id="diffFormButtonOk">OK</div>
-                <div id="diffFormButtonCancel">Cancel</div>
+        <div id="diffLayer" class="save-layer">
+            <div class="save-form diff-form">
+                <label for="diffFormSource">COMPARISON SOURCE</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="diffFormSource"
+                    placeholder="leave blank to use current snippet, or use snippet ID" class="save-form-title">
+
+                <label for="diffFormCompareTo">COMPARE TO</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="diffFormCompareTo" placeholder="snippet ID"
+                    class="save-form-title">
+
+                <div class="save-form-buttons" id="diffFormButtons">
+                    <div id="diffFormButtonOk">OK</div>
+                    <div id="diffFormButtonCancel">Cancel</div>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div id="waitDiv">
-        <div id="logo-part">
-            <img src="css/img/v4.svg" id="waitLogo" />
-            <img src="css/img/spinner.svg" id="waitSpinner" />
+        <div id="waitDiv">
+            <div id="logo-part">
+                <img src="css/img/v4.svg" id="waitLogo" />
+                <img src="css/img/spinner.svg" id="waitSpinner" />
+            </div>
         </div>
-    </div>
-
-    <!-- jQuery -->
-    <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="js/jquery.qrcode.js"></script>
-    <script src="js/qrcode.js"></script>
-
-    <!-- jQuery -->
-    <script src="js/libs/jquery.min.js"></script>
-    <script src="js/jquery.qrcode.js"></script>
-    <script src="js/qrcode.js"></script>
-
-    <!-- Main scripts -->
-    <script src="js/config_versions.js"></script>
-    <script src="js/pbt.js"></script>
-    <script src="js/examples.js"></script>
-    <script src="js/main.js"></script>
-    <script src="js/menuPG.js"></script>
-    <script src="js/monacoCreator.js"></script>
-    <script src="js/settingsPG.js"></script>
-    <script src="js/utils.js"></script>
-    <script src="js/zipTool.js"></script>
-    
-    <script>
-        BABYLONDEVTOOLS.Loader
-            .require('node_modules/monaco-editor/dev/vs/loader.js')
-            .require('js/index.js')
-            .load(function () {
-                BABYLON.DracoCompression.Configuration.decoder = {
-                    wasmUrl: "../dist/preview%20release/draco_wasm_wrapper_gltf.js",
-                    wasmBinaryUrl: "../dist/preview%20release/draco_decoder_gltf.wasm",
-                    fallbackUrl: "../dist/preview%20release/draco_decoder_gltf.js"
-                };
-                BABYLON.GLTFValidation.Configuration = {
-                    url: "../dist/preview%20release/gltf_validator.js"
-                };
-            });
-    </script>
-</body>
+
+        <!-- jQuery -->
+        <script src="https://code.jquery.com/jquery.js"></script>
+        <script src="https://rawcdn.githack.com/jeromeetienne/jquery-qrcode/master/jquery.qrcode.min.js"></script>
+
+        <!-- Main scripts -->
+        <script src="js/config_versions.js"></script>
+        <script src="js/examples.js"></script>
+        <script src="js/main.js"></script>
+        <script src="js/menuPG.js"></script>
+        <script src="js/monacoCreator.js"></script>
+        <script src="js/settingsPG.js"></script>
+        <script src="js/utils.js"></script>
+        <script src="js/zipTool.js"></script>
+
+        <script>
+            BABYLONDEVTOOLS.Loader
+                .require('node_modules/monaco-editor/dev/vs/loader.js')
+                .require('js/index.js')
+                .load(function () {
+                    BABYLON.DracoCompression.Configuration.decoder = {
+                        wasmUrl: "../dist/preview%20release/draco_wasm_wrapper_gltf.js",
+                        wasmBinaryUrl: "../dist/preview%20release/draco_decoder_gltf.wasm",
+                        fallbackUrl: "../dist/preview%20release/draco_decoder_gltf.js"
+                    };
+                    BABYLON.GLTFValidation.Configuration = {
+                        url: "../dist/preview%20release/gltf_validator.js"
+                    };
+                });
+        </script>
+    </body>
 
 </html>

+ 399 - 355
Playground/index.html

@@ -1,410 +1,454 @@
 <!DOCTYPE html>
 <html>
 
-<head>
-    <title>Babylon.js Playground</title>
-    <meta charset='utf-8' />
-    <meta name="viewport" content="width=device-width, user-scalable=no">
-    <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
-
-    <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css" />
-    <link rel="stylesheet" href="css/index.css" />
-    <link rel="stylesheet" href="css/index_mobile.css" />
-
-    <!-- Pep -->
-    <script src="js/libs/pep.min.js"></script>
-    <!-- For canvas/code separator -->
-    <script src="js/libs/split.js"></script>
-
-    <!-- DatGUI -->
-    <script src="js/libs/dat.gui.min.js"></script>
-    <!-- jszip -->
-    <script src="js/libs/jszip.min.js"></script>
-    <script src="js/libs/fileSaver.js"></script>
-
-    <!-- Dependencies -->
-    <script src="https://preview.babylonjs.com/ammo.js"></script>
-    <script src="https://preview.babylonjs.com/recast.js"></script>
-    <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/Oimo.js"></script>
-    <script src="https://preview.babylonjs.com/earcut.min.js"></script>
-    <!-- Babylon.js -->
-    <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/inspector/babylon.inspector.bundle.js"></script>
-    <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.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/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
-    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
-
-    <!-- Monaco -->
-    <script src="node_modules/monaco-editor/dev/vs/loader.js"></script>
-
-    <!-- Extensions -->
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js" async></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"
-        async></script>
-
-    <!-- Scene Manager -->
-    <script src="https://mackeyk24.github.io/toolkit/babylon.manager.js"></script>
-    <script src="https://mackeyk24.github.io/toolkit/babylon.navmesh.js"></script>
-</head>
-
-<body>
-    <!-- Big screens -->
-    <div class="navbar navBar1280 languageJS">
-        <div class="categoryTitle">
-            <img class="logo" src="css/img/logo_v4.svg">
-            <div class="version">Playground <span class="versionSub" id="mainTitle1280"></span></div>
-        </div>
+    <head>
+        <title>Babylon.js Playground</title>
+        <meta charset='utf-8' />
+        <meta name="viewport" content="width=device-width, user-scalable=no">
+        <meta name="description" content="Babylon.js playground is a live editor for Babylon.js WebGL 3D scenes">
+        <meta name="keywords" content="Babylon.js,WebGL,3D">
+        <meta name="google-site-verification" content="wcRjktXhF6DAjmhneKS7UatweBIkEF6QfqsNhAYbUgg" />
+        <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
+
+        <link rel="stylesheet"
+            href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" />
+        <link rel="stylesheet" href="/css/index.css" />
+        <link rel="stylesheet" href="/css/index_mobile.css" />
+
+    </head>
+
+    <body>
+        <!-- Big screens -->
+        <div class="navbar navBar1280 languageJS">
+            <div class="categoryTitle">
+                <img class="logo" src="/css/img/logo_v4.svg">
+                <div class="version">Playground <span class="versionSub" id="mainTitle1280"></span></div>
+            </div>
 
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonJStoTS languageTS" id="toTSbutton1280">Typescript</div>
-            <div class="buttonJStoTS languageJS" id="toJSbutton1280">Javascript</div>
-            <div class="buttonPG run removeOnDiff" id="runButton1280"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="newButton1280"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280"><img src="css/img/diffButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"><img src="css/img/previousButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"><img src="css/img/nextButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280"><img src="css/img/exitButton.svg"></div>
-            <div class="buttonPG select removeOnDiff" id="menuButton1280"><img src="css/img/optionsButton.svg">
-                <div class="toDisplay languageJS">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub languageJS">
-                            <div class="option selected" id="darkTheme1280">Dark</div>
-                            <div class="option" id="lightTheme1280">Light</div>
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonJStoTS languageTS" id="toTSbutton1280">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1280">JS</div>
+                <div class="buttonPG run removeOnDiff" id="runButton1280" title="Run&#10;(Alt+Enter)"><img
+                        src="/css/img/playButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="saveButton1280" title="Save&#10;(Ctrl+S)"><img
+                        src="/css/img/saveButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"
+                    title="Download ZIP&#10;(Ctrl+Shift+S)"><img src="/css/img/downloadButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="newButton1280" title="Create new"><img
+                        src="/css/img/newButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280" title="Clear"><img
+                        src="/css/img/clearButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280" title="Compare"><img
+                        src="/css/img/diffButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"
+                    title="Previous difference&#10;(Shift+Alt+F5)"><img src="/css/img/previousButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"
+                    title="Next difference&#10;(Alt+F5)"><img src="/css/img/nextButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280" title="Exit&#10;(Esc)"><img
+                        src="/css/img/exitButton.svg"></div>
+                <div class="buttonPG select removeOnDiff" id="menuButton1280" title="Options"><img
+                        src="/css/img/optionsButton.svg">
+                    <div class="toDisplay languageJS">
+                        <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub languageJS">
+                                <div class="option selected" id="darkTheme1280">Dark</div>
+                                <div class="option" id="lightTheme1280">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub displayFontSize languageJS">
-                            <div class="option">12</div>
-                            <div class="option selected">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub displayFontSize languageJS">
+                                <div class="option">12</div>
+                                <div class="option selected">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option noSubSelect" id="safemodeToggle1280">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option checked noSubSelect" id="editorButton1280">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option noSubSelect" id="fullscreenButton1280">Fullscreen</div>
-                    <div class="option noSubSelect" id="editorFullscreenButton1280">Editor Fullscreen</div>
-                    <div class="option noSubSelect" id="formatButton1280">Format code</div>
-                    <div class="option noSubSelect" id="minimapToggle1280">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option subSelect" id="qrCodeHover1280">QR Code Link <i class="fa fa-chevron-right"
-                            aria-hidden="true"></i>
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImage1280">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="safemodeToggle1280">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
                         </div>
+                        <div class="option checked noSubSelect" id="editorButton1280">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option noSubSelect" id="fullscreenButton1280">Fullscreen</div>
+                        <div class="option noSubSelect" id="editorFullscreenButton1280">Editor Fullscreen</div>
+                        <div class="option noSubSelect" id="formatButton1280">Format code</div>
+                        <div class="option noSubSelect" id="minimapToggle1280">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option subSelect" id="qrCodeHover1280">QR Code Link <i class="fa fa-chevron-right"
+                                aria-hidden="true"></i>
+                            <div class="toDisplaySub qrCodeImage">
+                                <div class="option" id="qrCodeImage1280">[QR Code Image]</div>
+                            </div>
+                        </div>
+                        <div class="option uncheck noSubSelect" id="debugButton1280">Inspector</div>
+                        <div class="option nosubselect" id="metadataButton1280">Metadata</div>
                     </div>
-                    <div class="option uncheck noSubSelect" id="debugButton1280">Inspector</div>
-                    <div class="option nosubselect" id="metadataButton1280">Metadata</div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="buttonPG select removeOnDiff">
-                <span id="currentVersion1280"></span>
-                <div class="toDisplay currentVersionDisplay" style="display: none"></div>
+            <div class="category right">
+                <div class="buttonPG select removeOnDiff" title="Select Babylon.js version">
+                    <span id="currentVersion1280"></span>
+                    <div class="toDisplay currentVersionDisplay" style="display: none"></div>
+                </div>
+                <div class="buttonPG select removeOnDiff" title="Examples"><img class="examplesButton"
+                        src="/css/img/examplesButton.svg"></div>
             </div>
-            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
-    </div>
 
-    <!-- Mid-size screens -->
-    <div class="navbar navBar1024 languageJS">
-        <div class="categoryTitle">
-            <img class="logo" src="css/img/logo_v4.svg">
-            <div class="version"><span class="versionSub" id="mainTitle1024"></span></div>
-        </div>
+        <!-- Mid-size screens -->
+        <div class="navbar navBar1024 languageJS">
+            <div class="categoryTitle">
+                <img class="logo" src="/css/img/logo_v4.svg">
+                <div class="version"><span class="versionSub" id="mainTitle1024"></span></div>
+            </div>
+
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
+                <div class="buttonSpaceKiller"></div>
+                <div class="buttonPG run removeOnDiff" id="runButton1024" title="Run&#10;(Alt+Enter)"><img
+                        src="/css/img/playButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="saveButton1024" title="Save&#10;(Ctrl+S)"><img
+                        src="/css/img/saveButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"
+                    title="Download ZIP&#10;(Ctrl+Shift+S)"><img src="/css/img/downloadButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="newButton1024" title="Create new"><img
+                        src="/css/img/newButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024" title="Clear"><img
+                        src="/css/img/clearButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024" title="Compare"><img
+                        src="/css/img/diffButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img
+                        src="/css/img/previousButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img
+                        src="/css/img/nextButton.svg">
+                </div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img
+                        src="/css/img/exitButton.svg">
+                </div>
+
+                <div class="buttonPG select removeOnDiff" id="menuButton1024" title="Options"><img
+                        src="/css/img/optionsButton.svg">
+                    <div class="toDisplay">
+                        <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
 
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
-            <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
-            <div class="buttonSpaceKiller"></div>
-            <div class="buttonPG run removeOnDiff" id="runButton1024"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG removeOnDiff" id="newButton1024"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024"><img src="css/img/diffButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img src="css/img/previousButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img src="css/img/nextButton.svg"></div>
-            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img src="css/img/exitButton.svg"></div>
-
-            <div class="buttonPG select removeOnDiff" id="menuButton1024"><img src="css/img/optionsButton.svg">
-                <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-
-                        <div class="toDisplaySub">
-                            <div class="option selected" id="darkTheme1024">Dark</div>
-                            <div class="option" id="lightTheme1024">Light</div>
+                            <div class="toDisplaySub">
+                                <div class="option selected" id="darkTheme1024">Dark</div>
+                                <div class="option" id="lightTheme1024">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub displayFontSize">
-                            <div class="option">12</div>
-                            <div class="option selected">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub displayFontSize">
+                                <div class="option">12</div>
+                                <div class="option selected">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option noSubSelect" id="safemodeToggle1024">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option checked noSubSelect" id="editorButton1024">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option noSubSelect" id="fullscreenButton1024">Fullscreen</div>
-                    <div class="option noSubSelect" id="editorFullscreenButton1024">Editor Fullscreen</div>
-                    <div class="option noSubSelect" id="formatButton1024">Format code</div>
-                    <div class="option noSubSelect" id="minimapToggle1024">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option subSelect" id="qrCodeHover1024">QR Code Link <i class="fa fa-chevron-right"
-                            aria-hidden="true"></i>
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImage1024">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="safemodeToggle1024">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
                         </div>
+                        <div class="option checked noSubSelect" id="editorButton1024">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option noSubSelect" id="fullscreenButton1024">Fullscreen</div>
+                        <div class="option noSubSelect" id="editorFullscreenButton1024">Editor Fullscreen</div>
+                        <div class="option noSubSelect" id="formatButton1024">Format code</div>
+                        <div class="option noSubSelect" id="minimapToggle1024">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option subSelect" id="qrCodeHover1024">QR Code Link <i class="fa fa-chevron-right"
+                                aria-hidden="true"></i>
+                            <div class="toDisplaySub qrCodeImage">
+                                <div class="option" id="qrCodeImage1024">[QR Code Image]</div>
+                            </div>
+                        </div>
+                        <div class="option uncheck noSubSelect" id="debugButton1024">Inspector</div>
+                        <div class="option noSubSelect" id="metadataButton1024">Metadata</div>
                     </div>
-                    <div class="option uncheck noSubSelect" id="debugButton1024">Inspector</div>
-                    <div class="option noSubSelect" id="metadataButton1024">Metadata</div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="buttonPG select removeOnDiff">
-                <span id="currentVersion1024"></span>
-                <div class="toDisplay currentVersionDisplay" style="display: none">
+            <div class="category right">
+                <div class="buttonPG select removeOnDiff" title="Select Babylon.js version">
+                    <span id="currentVersion1024"></span>
+                    <div class="toDisplay currentVersionDisplay" style="display: none">
+                    </div>
                 </div>
+                <div class="buttonPG select removeOnDiff" title="Examples"><img class="examplesButton"
+                        src="/css/img/examplesButton.svg"></div>
             </div>
-            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
-    </div>
-
-    <!-- Mobile -->
-    <div class="navbar navBarMobile languageJS">
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonPG select" id="menuButtonMobile"><img src="css/img/hamburgerButton.svg">
-                <div class="toDisplay">
-                    <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
-                    <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
-                    <div class="option noSubSelect run removeOnDiff" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
-                    <div class="option noSubSelect removeOnDiff" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
-                    <div class="option noSubSelect removeOnDiff" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download</div>
-                    <div class="option noSubSelect removeOnDiff" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
-                    <div class="option noSubSelect removeOnDiff" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear</div>
-                    <div class="option noSubSelect removeOnDiff" id="diffButtonMobile"><img src="css/img/DiffButton.svg">Diff</div>
-                    <div class="option noSubSelect displayOnDiff" id="previousButtonMobile"><img src="css/img/previousButton.svg">Previous</div>
-                    <div class="option noSubSelect displayOnDiff" id="nextButtonMobile"><img src="css/img/nextButton.svg">Next</div>
-                    <div class="option noSubSelect displayOnDiff" id="exitButtonMobile"><img src="css/img/exitButton.svg">Exit</div>
-
-                    <div class="option noSubSelect removeOnDiff" id="debugButtonMobile"><img
-                            src="css/img/inspectorButton.svg">Inspector</div>
-                    <div class="option subSelect removeOnDiff">
-                        <img src="css/img/optionsButton.svg">
-                        <div id="currentVersionMobile"></div>
-                        <div class="toDisplaySub currentVersionDisplay">
+
+        <!-- Mobile -->
+        <div class="navbar navBarMobile languageJS">
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonPG select" id="menuButtonMobile"><img src="/css/img/hamburgerButton.svg">
+                    <div class="toDisplay">
+                        <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
+                        <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
+                        <div class="option noSubSelect run removeOnDiff" id="runButtonMobile"><img
+                                src="/css/img/playButton.svg">Run</div>
+                        <div class="option noSubSelect removeOnDiff" id="saveButtonMobile"><img
+                                src="/css/img/saveButton.svg">Save</div>
+                        <div class="option noSubSelect removeOnDiff" id="zipButtonMobile"><img
+                                src="/css/img/downloadButton.svg">Download</div>
+                        <div class="option noSubSelect removeOnDiff" id="newButtonMobile"><img
+                                src="/css/img/newButton.svg">New</div>
+                        <div class="option noSubSelect removeOnDiff" id="clearButtonMobile"><img
+                                src="/css/img/clearButton.svg">Clear</div>
+                        <div class="option noSubSelect removeOnDiff" id="diffButtonMobile"><img
+                                src="/css/img/diffButton.svg">Diff</div>
+                        <div class="option noSubSelect displayOnDiff" id="previousButtonMobile"><img
+                                src="/css/img/previousButton.svg">Previous</div>
+                        <div class="option noSubSelect displayOnDiff" id="nextButtonMobile"><img
+                                src="/css/img/nextButton.svg">Next</div>
+                        <div class="option noSubSelect displayOnDiff" id="exitButtonMobile"><img
+                                src="/css/img/exitButton.svg">Exit</div>
+
+                        <div class="option noSubSelect removeOnDiff" id="debugButtonMobile"><img
+                                src="/css/img/inspectorButton.svg">Inspector</div>
+                        <div class="option subSelect removeOnDiff">
+                            <img src="/css/img/optionsButton.svg">
+                            <div id="currentVersionMobile"></div>
+                            <div class="toDisplaySub currentVersionDisplay">
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Theme
-                        <div class="toDisplaySub">
-                            <div class="option selected" id="darkThemeMobile">Dark</div>
-                            <div class="option" id="lightThemeMobile">Light</div>
+                        <div class="option subSelect removeOnDiff"><img src="/css/img/optionsButton.svg">Theme
+                            <div class="toDisplaySub">
+                                <div class="option selected" id="darkThemeMobile">Dark</div>
+                                <div class="option" id="lightThemeMobile">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Font size
-                        <div class="toDisplaySub displayFontSize">
-                            <div class="option">8</div>
-                            <div class="option">10</div>
-                            <div class="option selected">12</div>
-                            <div class="option">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect removeOnDiff"><img src="/css/img/optionsButton.svg">Font size
+                            <div class="toDisplaySub displayFontSize">
+                                <div class="option">8</div>
+                                <div class="option">10</div>
+                                <div class="option selected">12</div>
+                                <div class="option">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div style="display: none;" class="option noSubSelect" id="safemodeToggleMobile">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div style="display: none;" class="option checked noSubSelect" id="editorButtonMobile">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div style="display: none;" class="option nosubselect" id="fullscreenButtonMobile"
-                        style="display: none">Fullscreen</div>
-                    <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
-                        style="display: none">Editor
-                        Fullscreen</div>
-                    <div class="option nosubselect removeOnDiff" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
-                        code</div>
-                    <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <!-- <div class="option subSelect" id="qrCodeHoverMobile"><img src="css/img/optionsButton.svg">QR Code Link
+                        <div style="display: none;" class="option noSubSelect" id="safemodeToggleMobile">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div style="display: none;" class="option checked noSubSelect" id="editorButtonMobile">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div style="display: none;" class="option nosubselect" id="fullscreenButtonMobile"
+                            style="display: none">Fullscreen</div>
+                        <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
+                            style="display: none">Editor
+                            Fullscreen</div>
+                        <div class="option nosubselect removeOnDiff" id="formatButtonMobile"><img
+                                src="/css/img/optionsButton.svg">Format
+                            code</div>
+                        <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <!-- <div class="option subSelect" id="qrCodeHoverMobile"><img src="/css/img/optionsButton.svg">QR Code Link
                         <div class="toDisplaySub qrCodeImage">
                             <div class="option" id="qrCodeImageMobile">[QR Code Image]</div>
                         </div>
                     </div> -->
-                    <div class="option nosubselect removeOnDiff" id="metadataButtonMobile"><img
-                            src="css/img/metadataButton.svg">Metadata</div>
-                    <div class="option nosubselect removeOnDiff"><img class="examplesButton"
-                            src="css/img/examplesButton.svg">Examples</div>
-                    <div class="option subSelect removeOnDiff"><img src="css/img/examplesButton.svg">Links / Tools
-                        <div class="toDisplaySub displayFooterLinks">
-                            <div class="option link">
-                                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                        <div class="option nosubselect removeOnDiff" id="metadataButtonMobile"><img
+                                src="/css/img/metadataButton.svg">Metadata</div>
+                        <div class="option nosubselect removeOnDiff"><img class="examplesButton"
+                                src="/css/img/examplesButton.svg">Examples</div>
+                        <div class="option subSelect removeOnDiff"><img src="/css/img/examplesButton.svg">Links / Tools
+                            <div class="toDisplaySub displayFooterLinks">
+                                <div class="option link">
+                                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://sandbox.babylonjs.com/">Sandbox</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                                </div>
                             </div>
                         </div>
                     </div>
                 </div>
+                <div class="categoryTitle">
+                    <img class="logo" src="/css/img/logo_v4.svg">
+                    <div class="version"><span class="versionSub" id="mainTitleMobile"></span></div>
+                </div>
             </div>
-            <div class="categoryTitle">
-                <img class="logo" src="css/img/logo_v4.svg">
-                <div class="version"><span class="versionSub" id="mainTitleMobile"></span></div>
-            </div>
-        </div>
 
-        <div id="switchWrapper" class="languageJS removeOnDiff">
-            <img id="switchWrapperCode" src="css/img/codeButton.svg">
-            <img id="switchWrapperCanvas" src="css/img/canvas3Dbutton.svg">
+            <div id="switchWrapper" class="languageJS removeOnDiff">
+                <img id="switchWrapperCode" src="/css/img/codeButton.svg">
+                <img id="switchWrapperCanvas" src="/css/img/canvas3Dbutton.svg">
+            </div>
         </div>
-    </div>
 
-    <!-- Common things -->
+        <!-- Common things -->
 
-    <div class="wrapper">
-        <div id="jsEditor"></div>
-        <div id="diffView" class="diff-view"></div>
-        <div id="canvasZone">
-            <canvas touch-action="none" id="renderCanvas"></canvas>
-        </div>
-    </div>
-    <div id="exampleList" class="javascript">
-        <div id="exampleBanner" class="languageJS">
-            <h1>Examples<img id="examplesButtonClose" src="css/img/clearButton.svg"></h1>
-        </div>
-        <div class="horizontalSeparator"></div>
-        <input id="filterBar" type="text" placeholder="Filter examples...">
-        <img id="filterBarClear"
-            src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
-    </div>
-
-    <div class="fpsLabel languageJS" id="fpsLabel"></div>
-
-    <div id="errorZone">
-    </div>
-
-    <div class="navbarBottom">
-        <div id="statusBar"></div>
-        <div class="links">
-            <div class='link'>
-                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+        <div class="wrapper">
+            <div id="jsEditor"></div>
+            <div id="diffView" class="diff-view"></div>
+            <div id="canvasZone">
+                <canvas touch-action="none" id="renderCanvas"></canvas>
             </div>
-            <div class='link'>
-                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+        </div>
+        <div id="exampleList" class="javascript">
+            <div id="exampleBanner" class="languageJS">
+                <h1>Examples<img id="examplesButtonClose" src="/css/img/clearButton.svg"></h1>
             </div>
+            <div class="horizontalSeparator"></div>
+            <input id="filterBar" type="text" placeholder="Filter examples...">
+            <img id="filterBarClear" src="/css/img/clear_button.png">
+        </div>
+
+        <div class="fpsLabel languageJS" id="fpsLabel"></div>
+
+        <div id="errorZone">
         </div>
-    </div>
-
-    <div id="saveLayer" class="save-layer">
-        <div class="save-form languageJS ">
-            <img id="saveFormButtonClose" src="css/img/clearButton.svg">
-            <label for="saveFormTitle">TITLE</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
-
-            <label for="saveFormDescription">DESCRIPTION</label>
-            <div class="separator"></div>
-            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
-
-            <label for="saveFormTags">TAGS (separated by comma)</label>
-            <div class="separator"></div>
-            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
-
-            <div class="save-form-buttons" id="saveFormButtons">
-                <div id="saveFormButtonOk">OK</div>
-                <div id="saveFormButtonCancel">Cancel</div>
+
+        <div class="navbarBottom">
+            <div id="statusBar"></div>
+            <div class="links">
+                <div class='link'>
+                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div id="diffLayer" class="save-layer">
-        <div class="save-form diff-form">
-            <label for="diffFormSource">COMPARISON SOURCE</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="diffFormSource" placeholder="leave blank to use current snippet, or use snippet ID" class="save-form-title">
+        <div id="saveLayer" class="save-layer">
+            <div class="save-form languageJS ">
+                <img id="saveFormButtonClose" src="/css/img/clearButton.svg">
+                <label for="saveFormTitle">TITLE</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+
+                <label for="saveFormDescription">DESCRIPTION</label>
+                <div class="separator"></div>
+                <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+
+                <label for="saveFormTags">TAGS (separated by comma)</label>
+                <div class="separator"></div>
+                <textarea id="saveFormTags" rows="4" cols="10"></textarea>
 
-            <label for="diffFormCompareTo">COMPARE TO</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="diffFormCompareTo" placeholder="snippet ID" class="save-form-title">
+                <div class="save-form-buttons" id="saveFormButtons">
+                    <div id="saveFormButtonOk">OK</div>
+                    <div id="saveFormButtonCancel">Cancel</div>
+                </div>
+            </div>
+        </div>
 
-            <div class="save-form-buttons" id="diffFormButtons">
-                <div id="diffFormButtonOk">OK</div>
-                <div id="diffFormButtonCancel">Cancel</div>
+        <div id="diffLayer" class="save-layer">
+            <div class="save-form diff-form">
+                <label for="diffFormSource">COMPARISON SOURCE</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="diffFormSource"
+                    placeholder="leave blank to use current snippet, or use snippet ID" class="save-form-title">
+
+                <label for="diffFormCompareTo">COMPARE TO</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="diffFormCompareTo" placeholder="snippet ID"
+                    class="save-form-title">
+
+                <div class="save-form-buttons" id="diffFormButtons">
+                    <div id="diffFormButtonOk">OK</div>
+                    <div id="diffFormButtonCancel">Cancel</div>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div id="waitDiv">
-        <div id="logo-part">
-            <img src="css/img/v4.svg" id="waitLogo" />
-            <img src="css/img/spinner.svg" id="waitSpinner" />
+        <div id="waitDiv">
+            <div id="logo-part">
+                <img src="/css/img/v4.svg" id="waitLogo" />
+                <img src="/css/img/spinner.svg" id="waitSpinner" />
+            </div>
         </div>
-    </div>
-
-    <!-- jQuery -->
-    <script src="js/libs/jquery.min.js"></script>
-    <script src="js/jquery.qrcode.js"></script>
-    <script src="js/qrcode.js"></script>
-
-    <!-- Main scripts -->
-    <script src="js/config_versions.js"></script>
-    <script src="js/pbt.js"></script>
-    <script src="js/examples.js"></script>
-    <script src="js/main.js"></script>
-    <script src="js/menuPG.js"></script>
-    <script src="js/monacoCreator.js"></script>
-    <script src="js/settingsPG.js"></script>
-    <script src="js/utils.js"></script>
-    <script src="js/zipTool.js"></script>
-    <script src="js/index.js"></script>
-</body>
+
+
+        <!-- Pep -->
+        <script src="/js/libs/pep.min.js"></script>
+        <!-- For canvas/code separator -->
+        <script src="/js/libs/split.js"></script>
+
+        <!-- DatGUI -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <!-- jszip -->
+        <script src="/js/libs/jszip.min.js"></script>
+        <script src="/js/libs/fileSaver.js"></script>
+
+        <!-- Babylon.js -->
+        <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/inspector/babylon.inspector.bundle.js"></script>
+        <script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.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/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
+        <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
+
+         <!-- Dependencies -->
+         <script src="https://preview.babylonjs.com/ammo.js"></script>
+         <script src="https://preview.babylonjs.com/earcut.min.js"></script>
+         <script src="https://preview.babylonjs.com/recast.js"></script>
+         <script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.min.js"></script>
+         <script src="https://cdnjs.cloudflare.com/ajax/libs/oimo/1.0.9/oimo.min.js"></script>
+         <script src="https://preview.babylonjs.com/libktx.js"></script>
+ 
+         <!-- Extensions -->
+         <script
+             src="https://rawcdn.githack.com/BabylonJS/Extensions/f43ab677b4bca0a6ab77132d3f785be300382760/ClonerSystem/src/babylonx.cloner.js"
+             >
+         </script>
+         <script
+             src="https://rawcdn.githack.com/BabylonJS/Extensions/785013ec55b210d12263c91f3f0a2ae70cf0bc8a/CompoundShader/src/babylonx.CompoundShader.js"
+             ></script>
+ 
+         <!-- Scene Manager -->
+         <script
+             src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.manager.js">
+         </script>
+         <script
+             src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.navmesh.js">
+         </script>
+
+        <!-- Monaco -->
+        <script src="/node_modules/monaco-editor/dev/vs/loader.js"></script>
+
+        <!-- jQuery -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>
+
+        <!-- Main scripts -->
+        <script src="/js/config_versions.js"></script>
+        <script src="/js/examples.js"></script>
+        <script src="/js/main.js"></script>
+        <script src="/js/menuPG.js"></script>
+        <script src="/js/monacoCreator.js"></script>
+        <script src="/js/settingsPG.js"></script>
+        <script src="/js/utils.js"></script>
+        <script src="/js/zipTool.js"></script>
+        <script src="/js/index.js"></script>
+    </body>
 
 </html>

+ 379 - 336
Playground/indexStable.html

@@ -1,386 +1,429 @@
 <!DOCTYPE html>
 <html>
 
-<head>
-    <title>Babylon.js Playground</title>
-    <meta charset='utf-8' />
-    <meta name="viewport" content="width=device-width, user-scalable=no">
-    <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
-
-    <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css" />
-    <link rel="stylesheet" href="css/index.css" />
-    <link rel="stylesheet" href="css/index_mobile.css" />
-
-    <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
-    <meta name="msapplication-TileColor" content="#ffffff">
-    <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-    <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-    <meta name="theme-color" content="#ffffff">
-
-    <!-- Pep -->
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <!--For canvas/code separator-->
-    <script src="js/libs/split.js"></script>
-
-    <!-- DatGUI -->
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-    <!-- jszip -->
-    <script src="js/libs/jszip.min.js"></script>
-    <script src="js/libs/fileSaver.js"></script>
-
-    <!-- Dependencies -->
-    <script src="https://cdn.babylonjs.com/ammo.js"></script>
-    <script src="https://cdn.babylonjs.com/cannon.js"></script>
-    <script src="https://cdn.babylonjs.com/Oimo.js"></script>
-    <script src="https://cdn.babylonjs.com/gltf_validator.js"></script>
-    <script src="https://cdn.babylonjs.com/earcut.min.js"></script>
-    <!-- Babylon.js -->
-    <script src="https://cdn.babylonjs.com/babylon.js"></script>
-    <script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script>
-    <script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
-    <script src="https://cdn.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
-    <script src="https://cdn.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
-    <script src="https://cdn.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
-    <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.js"></script>
-    <script src="https://cdn.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
-
-    <!-- Monaco -->
-    <script src="node_modules/monaco-editor/dev/vs/loader.js"></script>
-
-    <!-- Extensions -->
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
-</head>
-
-<body>
-    <!-- Big screens -->
-    <div class="navbar navBar1280 languageJS">
-        <div class="categoryTitle">
-            <img class="logo" src="css/img/logo_v4.svg">
-            <div class="version">Playground <span class="versionSub" id="mainTitle1280"></span></div>
-        </div>
+    <head>
+        <title>Babylon.js Playground</title>
+        <meta charset='utf-8' />
+        <meta name="viewport" content="width=device-width, user-scalable=no">
+        <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
+
+        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" />
+        <link rel="stylesheet" href="/css/index.css" />
+        <link rel="stylesheet" href="/css/index_mobile.css" />
+
+        <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
+        <meta name="msapplication-TileColor" content="#ffffff">
+        <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
+        <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
+        <meta name="theme-color" content="#ffffff">
+    </head>
+
+    <body>
+        <!-- Big screens -->
+        <div class="navbar navBar1280 languageJS">
+            <div class="categoryTitle">
+                <img class="logo" src="/css/img/logo_v4.svg">
+                <div class="version">Playground <span class="versionSub" id="mainTitle1280"></span></div>
+            </div>
 
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonJStoTS languageTS" id="toTSbutton1280">Typescript</div>
-            <div class="buttonJStoTS languageJS" id="toJSbutton1280">Javascript</div>
-            <div class="button run" id="runButton1280"><img src="css/img/playButton.svg"></div>
-            <div class="button" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
-            <div class="button removeOnPhone" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
-            <div class="button" id="newButton1280"><img src="css/img/newButton.svg"></div>
-            <div class="button removeOnPhone" id="clearButton1280"><img src="css/img/clearButton.svg"></div>
-            <div class="button select" id="menuButton1280"><img src="css/img/optionsButton.svg">
-                <div class="toDisplay languageJS">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub languageJS">
-                            <div class="option selected" id="darkTheme1280">Dark</div>
-                            <div class="option" id="lightTheme1280">Light</div>
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonJStoTS languageTS" id="toTSbutton1280" title="Switch to TypeScript">Typescript</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1280" title="Switch to JavaScript">Javascript</div>
+                <div class="buttonPG run removeOnDiff" id="runButton1280" title="Run&#10;(Alt+Enter)"><img
+                        src="/css/img/playButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="saveButton1280" title="Save&#10;(Ctrl+S)"><img
+                        src="/css/img/saveButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"
+                    title="Download ZIP&#10;(Ctrl+Shift+S)"><img src="/css/img/downloadButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="newButton1280" title="Create new"><img
+                        src="/css/img/newButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280" title="Clear"><img
+                        src="/css/img/clearButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280" title="Compare"><img
+                        src="/css/img/diffButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"
+                    title="Previous difference&#10;(Shift+Alt+F5)"><img src="/css/img/previousButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"
+                    title="Next difference&#10;(Alt+F5)"><img src="/css/img/nextButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280" title="Exit&#10;(Esc)"><img
+                        src="/css/img/exitButton.svg"></div>
+                <div class="buttonPG select removeOnDiff" id="menuButton1280" title="Options"><img
+                        src="/css/img/optionsButton.svg">
+                    <div class="toDisplay languageJS">
+                        <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub languageJS">
+                                <div class="option selected" id="darkTheme1280">Dark</div>
+                                <div class="option" id="lightTheme1280">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub displayFontSize languageJS">
-                            <div class="option">12</div>
-                            <div class="option selected">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub displayFontSize languageJS">
+                                <div class="option">12</div>
+                                <div class="option selected">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option noSubSelect" id="safemodeToggle1280">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option checked noSubSelect" id="editorButton1280">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option noSubSelect" id="fullscreenButton1280">Fullscreen</div>
-                    <div class="option noSubSelect" id="editorFullscreenButton1280">Editor Fullscreen</div>
-                    <div class="option noSubSelect" id="formatButton1280">Format code</div>
-                    <div class="option noSubSelect" id="minimapToggle1280">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option subSelect" id="qrCodeHover1280">QR Code Link <i class="fa fa-chevron-right"
-                            aria-hidden="true"></i>
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImage1280">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="safemodeToggle1280">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
                         </div>
+                        <div class="option checked noSubSelect" id="editorButton1280">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option noSubSelect" id="fullscreenButton1280">Fullscreen</div>
+                        <div class="option noSubSelect" id="editorFullscreenButton1280">Editor Fullscreen</div>
+                        <div class="option noSubSelect" id="formatButton1280">Format code</div>
+                        <div class="option noSubSelect" id="minimapToggle1280">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option subSelect" id="qrCodeHover1280">QR Code Link <i class="fa fa-chevron-right"
+                                aria-hidden="true"></i>
+                            <div class="toDisplaySub qrCodeImage">
+                                <div class="option" id="qrCodeImage1280">[QR Code Image]</div>
+                            </div>
+                        </div>
+                        <div class="option uncheck noSubSelect" id="debugButton1280">Inspector</div>
+                        <div class="option nosubselect" id="metadataButton1280">Metadata</div>
                     </div>
-                    <div class="option uncheck noSubSelect" id="debugButton1280">Inspector</div>
-                    <div class="option nosubselect" id="metadataButton1280">Metadata</div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="button select">
-                <span id="currentVersion1280"></span>
-                <div class="toDisplay currentVersionDisplay" style="display: none"></div>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentVersion1280"></span>
+                    <div class="toDisplay currentVersionDisplay" style="display: none"></div>
+                </div>
+                <div class="button select"><img class="examplesButton" src="/css/img/examplesButton.svg"></div>
             </div>
-            <div class="button select"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
-    </div>
 
-    <!-- Mid-size screens -->
-    <div class="navbar navBar1024 languageJS">
-        <div class="categoryTitle">
-            <img class="logo" src="css/img/logo_v4.svg">
-            <div class="version"><span class="versionSub" id="mainTitle1024"></span></div>
-        </div>
+        <!-- Mid-size screens -->
+        <div class="navbar navBar1024 languageJS">
+            <div class="categoryTitle">
+                <img class="logo" src="/css/img/logo_v4.svg">
+                <div class="version"><span class="versionSub" id="mainTitle1024"></span></div>
+            </div>
 
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
-            <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
-            <div class="buttonSpaceKiller"></div>
-            <div class="button run" id="runButton1024"><img src="css/img/playButton.svg"></div>
-            <div class="button" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
-            <div class="button removeOnPhone" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
-            <div class="button" id="newButton1024"><img src="css/img/newButton.svg"></div>
-            <div class="button removeOnPhone" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
-
-            <div class="button select" id="menuButton1024"><img src="css/img/optionsButton.svg">
-                <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-
-                        <div class="toDisplaySub">
-                            <div class="option selected" id="darkTheme1024">Dark</div>
-                            <div class="option" id="lightTheme1024">Light</div>
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonJStoTS languageTS" id="toTSbutton1024" title="Switch to TypeScript">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1024" title="Switch to JavaScript">JS</div>
+                <div class="buttonSpaceKiller"></div>
+                <div class="buttonPG run removeOnDiff" id="runButton1024" title="Run&#10;(Alt+Enter)"><img
+                        src="/css/img/playButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="saveButton1024" title="Save&#10;(Ctrl+S)"><img
+                        src="/css/img/saveButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"
+                    title="Download ZIP&#10;(Ctrl+Shift+S)"><img src="/css/img/downloadButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="newButton1024" title="Create new"><img
+                        src="/css/img/newButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024" title="Clear"><img
+                        src="/css/img/clearButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024" title="Compare"><img
+                        src="/css/img/diffButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img
+                        src="/css/img/previousButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img
+                        src="/css/img/nextButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img
+                        src="/css/img/exitButton.svg"></div>
+
+                <div class="buttonPG select removeOnDiff" id="menuButton1024" title="Options"><img
+                        src="/css/img/optionsButton.svg">
+                    <div class="toDisplay">
+                        <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+
+                            <div class="toDisplaySub">
+                                <div class="option selected" id="darkTheme1024">Dark</div>
+                                <div class="option" id="lightTheme1024">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub displayFontSize">
-                            <div class="option">12</div>
-                            <div class="option selected">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub displayFontSize">
+                                <div class="option">12</div>
+                                <div class="option selected">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option noSubSelect" id="safemodeToggle1024">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option checked noSubSelect" id="editorButton1024">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option noSubSelect" id="fullscreenButton1024">Fullscreen</div>
-                    <div class="option noSubSelect" id="editorFullscreenButton1024">Editor Fullscreen</div>
-                    <div class="option noSubSelect" id="formatButton1024">Format code</div>
-                    <div class="option noSubSelect" id="minimapToggle1024">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option subSelect" id="qrCodeHover1024">QR Code Link <i class="fa fa-chevron-right"
-                            aria-hidden="true"></i>
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImage1024">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="safemodeToggle1024">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option checked noSubSelect" id="editorButton1024">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option noSubSelect" id="fullscreenButton1024">Fullscreen</div>
+                        <div class="option noSubSelect" id="editorFullscreenButton1024">Editor Fullscreen</div>
+                        <div class="option noSubSelect" id="formatButton1024">Format code</div>
+                        <div class="option noSubSelect" id="minimapToggle1024">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option subSelect" id="qrCodeHover1024">QR Code Link <i class="fa fa-chevron-right"
+                                aria-hidden="true"></i>
+                            <div class="toDisplaySub qrCodeImage">
+                                <div class="option" id="qrCodeImage1024">[QR Code Image]</div>
+                            </div>
                         </div>
+                        <div class="option uncheck noSubSelect" id="debugButton1024">Inspector</div>
+                        <div class="option noSubSelect" id="metadataButton1024">Metadata</div>
                     </div>
-                    <div class="option uncheck noSubSelect" id="debugButton1024">Inspector</div>
-                    <div class="option noSubSelect" id="metadataButton1024">Metadata</div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="button select">
-                <span id="currentVersion1024"></span>
-                <div class="toDisplay currentVersionDisplay" style="display: none">
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentVersion1024"></span>
+                    <div class="toDisplay currentVersionDisplay" style="display: none">
+                    </div>
                 </div>
+                <div class="button select"><img class="examplesButton" src="/css/img/examplesButton.svg"></div>
             </div>
-            <div class="button select"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
-    </div>
-
-    <!-- Mobile -->
-    <div class="navbar navBarMobile languageJS">
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="button select" id="menuButtonMobile"><img src="css/img/hamburgerButton.svg">
-                <div class="toDisplay">
-                    <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
-                    <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
-                    <div class="option noSubSelect run" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
-                    <div class="option noSubSelect" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
-                    <div class="option noSubSelect" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download
-                    </div>
-                    <div class="option noSubSelect" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
-                    <div class="option noSubSelect" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear
-                    </div>
-                    <div class="option noSubSelect" id="debugButtonMobile"><img
-                            src="css/img/inspectorButton.svg">Inspector</div>
-                    <div class="option subSelect">
-                        <img src="css/img/optionsButton.svg">
-                        Version<div id="currentVersionMobile"></div>
-                        <div class="toDisplaySub currentVersionDisplay">
+
+        <!-- Mobile -->
+        <div class="navbar navBarMobile languageJS">
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="button select" id="menuButtonMobile"><img src="/css/img/hamburgerButton.svg">
+                    <div class="toDisplay">
+                        <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
+                        <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
+                        <div class="option noSubSelect run" id="runButtonMobile"><img src="/css/img/playButton.svg">Run
                         </div>
-                    </div>
-                    <div class="option subSelect"><img src="css/img/optionsButton.svg">Theme
-                        <div class="toDisplaySub">
-                            <div class="option selected" id="darkThemeMobile">Dark</div>
-                            <div class="option" id="lightThemeMobile">Light</div>
+                        <div class="option noSubSelect" id="saveButtonMobile"><img src="/css/img/saveButton.svg">Save
                         </div>
-                    </div>
-                    <div class="option subSelect"><img src="css/img/optionsButton.svg">Font size
-                        <div class="toDisplaySub displayFontSize">
-                            <div class="option">8</div>
-                            <div class="option">10</div>
-                            <div class="option selected">12</div>
-                            <div class="option">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option noSubSelect" id="zipButtonMobile"><img
+                                src="/css/img/downloadButton.svg">Download
                         </div>
-                    </div>
-                    <div style="display: none;" class="option noSubSelect" id="safemodeToggleMobile">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div style="display: none;" class="option checked noSubSelect" id="editorButtonMobile">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div style="display: none;" class="option nosubselect" id="fullscreenButtonMobile"
-                        style="display: none">Fullscreen</div>
-                    <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
-                        style="display: none">Editor
-                        Fullscreen</div>
-                    <div class="option nosubselect" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
-                        code</div>
-                    <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <!-- <div class="option subSelect" id="qrCodeHoverMobile"><img src="css/img/optionsButton.svg">QR Code Link
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImageMobile">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="newButtonMobile"><img src="/css/img/newButton.svg">New</div>
+                        <div class="option noSubSelect" id="clearButtonMobile"><img src="/css/img/clearButton.svg">Clear
                         </div>
-                    </div> -->
-                    <div class="option nosubselect" id="metadataButtonMobile"><img
-                            src="css/img/metadataButton.svg">Metadata</div>
-                    <div class="option nosubselect"><img class="examplesButton"
-                            src="css/img/examplesButton.svg">Examples</div>
-                    <div class="option subSelect"><img src="css/img/examplesButton.svg">Links / Tools
-                        <div class="toDisplaySub displayFooterLinks">
-                            <div class="option link">
-                                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                        <div class="option noSubSelect" id="debugButtonMobile"><img
+                                src="/css/img/inspectorButton.svg">Inspector</div>
+                        <div class="option subSelect">
+                            <img src="/css/img/optionsButton.svg">
+                            Version<div id="currentVersionMobile"></div>
+                            <div class="toDisplaySub currentVersionDisplay">
                             </div>
-                            <div class="option link">
-                                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                        </div>
+                        <div class="option subSelect"><img src="/css/img/optionsButton.svg">Theme
+                            <div class="toDisplaySub">
+                                <div class="option selected" id="darkThemeMobile">Dark</div>
+                                <div class="option" id="lightThemeMobile">Light</div>
                             </div>
-                            <div class="option link">
-                                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                        </div>
+                        <div class="option subSelect"><img src="/css/img/optionsButton.svg">Font size
+                            <div class="toDisplaySub displayFontSize">
+                                <div class="option">8</div>
+                                <div class="option">10</div>
+                                <div class="option selected">12</div>
+                                <div class="option">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
                             </div>
-                            <div class="option link">
-                                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                        </div>
+                        <div style="display: none;" class="option noSubSelect" id="safemodeToggleMobile">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div style="display: none;" class="option checked noSubSelect" id="editorButtonMobile">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div style="display: none;" class="option nosubselect" id="fullscreenButtonMobile"
+                            style="display: none">Fullscreen</div>
+                        <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
+                            style="display: none">Editor
+                            Fullscreen</div>
+                        <div class="option nosubselect" id="formatButtonMobile"><img
+                                src="/css/img/optionsButton.svg">Format
+                            code</div>
+                        <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <!-- <div class="option subSelect" id="qrCodeHoverMobile"><img src="/css/img/optionsButton.svg">QR Code Link
+                        <div class="toDisplaySub qrCodeImage">
+                            <div class="option" id="qrCodeImageMobile">[QR Code Image]</div>
+                        </div>
+                    </div> -->
+                        <div class="option nosubselect" id="metadataButtonMobile"><img
+                                src="/css/img/metadataButton.svg">Metadata</div>
+                        <div class="option nosubselect"><img class="examplesButton"
+                                src="/css/img/examplesButton.svg">Examples</div>
+                        <div class="option subSelect"><img src="/css/img/examplesButton.svg">Links / Tools
+                            <div class="toDisplaySub displayFooterLinks">
+                                <div class="option link">
+                                    <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                                </div>
                             </div>
                         </div>
                     </div>
                 </div>
+                <div class="categoryTitle">
+                    <img class="logo" src="/css/img/logo_v4.svg">
+                    <div class="version"><span class="versionSub" id="mainTitleMobile"></span></div>
+                </div>
             </div>
-            <div class="categoryTitle">
-                <img class="logo" src="css/img/logo_v4.svg">
-                <div class="version"><span class="versionSub" id="mainTitleMobile"></span></div>
+
+            <div id="switchWrapper" class="languageJS">
+                <img id="switchWrapperCode" src="/css/img/codeButton.svg">
+                <img id="switchWrapperCanvas" src="/css/img/canvas3Dbutton.svg">
             </div>
         </div>
 
-        <div id="switchWrapper" class="languageJS">
-            <img id="switchWrapperCode" src="css/img/codeButton.svg">
-            <img id="switchWrapperCanvas" src="css/img/canvas3Dbutton.svg">
+        <!-- Common things -->
+
+        <div class="wrapper">
+            <div id="jsEditor"></div>
+            <div id="canvasZone">
+                <canvas touch-action="none" id="renderCanvas"></canvas>
+            </div>
+        </div>
+        <div id="exampleList" class="javascript">
+            <div id="exampleBanner" class="languageJS">
+                <h1>Examples<img id="examplesButtonClose" src="/css/img/clearButton.svg"></h1>
+            </div>
+            <div class="horizontalSeparator"></div>
+            <input id="filterBar" type="text" placeholder="Filter examples...">
+            <img id="filterBarClear"
+                src="/css/img/clear_button.png">
         </div>
-    </div>
 
-    <!-- Common things -->
+        <div class="fpsLabel languageJS" id="fpsLabel"></div>
 
-    <div class="wrapper">
-        <div id="jsEditor"></div>
-        <div id="canvasZone">
-            <canvas touch-action="none" id="renderCanvas"></canvas>
-        </div>
-    </div>
-    <div id="exampleList" class="javascript">
-        <div id="exampleBanner" class="languageJS">
-            <h1>Examples<img id="examplesButtonClose" src="css/img/clearButton.svg"></h1>
+        <div id="errorZone">
         </div>
-        <div class="horizontalSeparator"></div>
-        <input id="filterBar" type="text" placeholder="Filter examples...">
-        <img id="filterBarClear"
-            src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
-    </div>
-
-    <div class="fpsLabel languageJS" id="fpsLabel"></div>
-
-    <div id="errorZone">
-    </div>
-
-    <div class="navbarBottom">
-        <div id="statusBar"></div>
-        <div class="links">
-            <div class='link'>
-                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+
+        <div class="navbarBottom">
+            <div id="statusBar"></div>
+            <div class="links">
+                <div class='link'>
+                    <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                </div>
             </div>
         </div>
-    </div>
-
-    <div id="saveLayer" class="save-layer">
-        <div class="save-form languageJS ">
-            <img id="saveFormButtonClose" src="css/img/clearButton.svg">
-            <label for="saveFormTitle">TITLE</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
-
-            <label for="saveFormDescription">DESCRIPTION</label>
-            <div class="separator"></div>
-            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
-
-            <label for="saveFormTags">TAGS (separated by comma)</label>
-            <div class="separator"></div>
-            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
-
-            <div class="save-form-buttons" id="saveFormButtons">
-                <div id="saveFormButtonOk">OK</div>
-                <div id="saveFormButtonCancel">Cancel</div>
+
+        <div id="saveLayer" class="save-layer">
+            <div class="save-form languageJS ">
+                <img id="saveFormButtonClose" src="/css/img/clearButton.svg">
+                <label for="saveFormTitle">TITLE</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+
+                <label for="saveFormDescription">DESCRIPTION</label>
+                <div class="separator"></div>
+                <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+
+                <label for="saveFormTags">TAGS (separated by comma)</label>
+                <div class="separator"></div>
+                <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+
+                <div class="save-form-buttons" id="saveFormButtons">
+                    <div id="saveFormButtonOk">OK</div>
+                    <div id="saveFormButtonCancel">Cancel</div>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div id="waitDiv">
-        <div id="logo-part">
-            <img src="css/img/v4.svg" id="waitLogo" />
-            <img src="css/img/spinner.svg" id="waitSpinner" />
+        <div id="waitDiv">
+            <div id="logo-part">
+                <img src="/css/img/v4.svg" id="waitLogo" />
+                <img src="/css/img/spinner.svg" id="waitSpinner" />
+            </div>
         </div>
-    </div>
-
-    <!-- jQuery -->
-    <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="js/jquery.qrcode.js"></script>
-    <script src="js/qrcode.js"></script>
-
-    <!-- TO DO - Why is this a split here ? It's already in the JS code (index.js) -->
-    <script>
-        Split(['#jsEditor', '#canvasZone']);
-    </script>
-
-    <!-- Main scripts -->
-    <script src="js/config_versions.js"></script>
-    <script src="js/pbt.js"></script>
-    <script src="js/libs/typescript.js"></script>
-    <script src="js/examples.js"></script>
-    <script src="js/main.js"></script>
-    <script src="js/menuPG.js"></script>
-    <script src="js/monacoCreator.js"></script>
-    <script src="js/settingsPG.js"></script>
-    <script src="js/utils.js"></script>
-    <script src="js/zipTool.js"></script>
-    <script src="js/index.js"></script>
-</body>
-
-</html>
+
+        <!-- Pep -->
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+        <!--For canvas/code separator-->
+        <script src="/js/libs/split.js"></script>
+
+        <!-- DatGUI -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <!-- jszip -->
+        <script src="/js/libs/jszip.min.js"></script>
+        <script src="/js/libs/fileSaver.js"></script>
+
+        <!-- Dependencies -->
+        <script src="https://cdn.babylonjs.com/ammo.js"></script>
+        <script src="https://cdn.babylonjs.com/cannon.js"></script>
+        <script src="https://cdn.babylonjs.com/Oimo.js"></script>
+        <script src="https://cdn.babylonjs.com/gltf_validator.js"></script>
+        <script src="https://cdn.babylonjs.com/earcut.min.js"></script>
+        <!-- Babylon.js -->
+        <script src="https://cdn.babylonjs.com/babylon.js"></script>
+        <script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script>
+        <script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+        <script src="https://cdn.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
+        <script src="https://cdn.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
+        <script src="https://cdn.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
+        <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.js"></script>
+        <script src="https://cdn.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
+
+        <!-- Monaco -->
+        <script src="/node_modules/monaco-editor/dev/vs/loader.js"></script>
+
+        <!-- Extensions -->
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/f43ab677b4bca0a6ab77132d3f785be300382760/ClonerSystem/src/babylonx.cloner.js"
+            async>
+        </script>
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/785013ec55b210d12263c91f3f0a2ae70cf0bc8a/CompoundShader/src/babylonx.CompoundShader.js"
+            async></script>
+
+        <!-- Scene Manager -->
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.manager.js">
+        </script>
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.navmesh.js">
+        </script>
+
+        <!-- jQuery -->
+        <script src="https://code.jquery.com/jquery.min.js"></script>
+        <script src="https://rawcdn.githack.com/jeromeetienne/jquery-qrcode/master/jquery.qrcode.min.js"></script>
+
+        <!-- TO DO - Why is this a split here ? It's already in the JS code (index.js) -->
+        <script>
+            Split(['#jsEditor', '#canvasZone']);
+        </script>
+
+        <!-- Main scripts -->
+        <script src="/js/config_versions.js"></script>
+        <script src="/js/examples.js"></script>
+        <script src="/js/main.js"></script>
+        <script src="/js/menuPG.js"></script>
+        <script src="/js/monacoCreator.js"></script>
+        <script src="/js/settingsPG.js"></script>
+        <script src="/js/utils.js"></script>
+        <script src="/js/zipTool.js"></script>
+        <script src="/js/index.js"></script>
+    </body>
+
+</html>

+ 352 - 312
Playground/indexWebGPU.html

@@ -1,384 +1,424 @@
 <!DOCTYPE html>
 <html>
 
-<head>
-    <title>Babylon.js Playground WEBGPU</title>
-    <meta charset='utf-8' />
-    <meta name="viewport" content="width=device-width, user-scalable=no">
-    <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
+    <head>
+        <title>Babylon.js Playground WEBGPU</title>
+        <meta charset='utf-8' />
+        <meta name="viewport" content="width=device-width, user-scalable=no">
+        <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
 
-    <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css" />
-    <link rel="stylesheet" href="css/index.css" />
-    <link rel="stylesheet" href="css/index_mobile.css" />
+        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" />
+        <link rel="stylesheet" href="/css/index.css" />
+        <link rel="stylesheet" href="/css/index_mobile.css" />
 
-    <!-- Pep -->
-    <script src="js/libs/pep.min.js"></script>
-    <!-- For canvas/code separator -->
-    <script src="js/libs/split.js"></script>
+        <!-- Pep -->
+        <script src="/js/libs/pep.min.js"></script>
+        <!-- For canvas/code separator -->
+        <script src="/js/libs/split.js"></script>
 
-    <!-- DatGUI -->
-    <script src="js/libs/dat.gui.min.js"></script>
-    <!-- jszip -->
-    <script src="js/libs/jszip.min.js"></script>
-    <script src="js/libs/fileSaver.js"></script>
+        <!-- DatGUI -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <!-- jszip -->
+        <script src="/js/libs/jszip.min.js"></script>
+        <script src="/js/libs/fileSaver.js"></script>
 
-    <!-- Dependencies -->
-    <script src="https://preview.babylonjs.com/ammo.js"></script>
-    <script src="https://preview.babylonjs.com/recast.js"></script>
-    <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/Oimo.js"></script>
-    <script src="https://preview.babylonjs.com/earcut.min.js"></script>
-    <!-- Babylon.js -->
-    <script src="https://preview.babylonjs.com/glslang/glslang.js"></script>
-    <script src="js/babylonWebGpu.max.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/nodeEditor/babylon.nodeEditor.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>
+        <!-- Dependencies -->
+        <script src="https://preview.babylonjs.com/ammo.js"></script>
+        <script src="https://preview.babylonjs.com/recast.js"></script>
+        <script src="https://preview.babylonjs.com/cannon.js"></script>
+        <script src="https://preview.babylonjs.com/Oimo.js"></script>
+        <script src="https://preview.babylonjs.com/libktx.js"></script>
+        <script src="https://preview.babylonjs.com/earcut.min.js"></script>
+        <!-- Babylon.js -->
+        <script src="https://preview.babylonjs.com/glslang/glslang.js"></script>
+        <script src="/js/babylonWebGpu.max.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/nodeEditor/babylon.nodeEditor.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/postProcessesLibrary/babylonjs.postProcess.min.js"></script> -->
-    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
-    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
+        <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
 
-    <!-- Monaco -->
-    <script src="node_modules/monaco-editor/dev/vs/loader.js"></script>
+        <!-- Monaco -->
+        <script src="/node_modules/monaco-editor/min/vs/loader.js"></script>
 
-    <!-- Extensions -->
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js" async></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"
-        async></script>
+        <!-- Extensions -->
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/f43ab677b4bca0a6ab77132d3f785be300382760/ClonerSystem/src/babylonx.cloner.js"
+            async>
+        </script>
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/785013ec55b210d12263c91f3f0a2ae70cf0bc8a/CompoundShader/src/babylonx.CompoundShader.js"
+            async></script>
 
-    <!-- Scene Manager -->
-    <script src="https://mackeyk24.github.io/toolkit/babylon.manager.js"></script>
-    <script src="https://mackeyk24.github.io/toolkit/babylon.navmesh.js"></script>
-</head>
+        <!-- Scene Manager -->
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.manager.js">
+        </script>
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.navmesh.js">
+        </script>
+    </head>
 
-<body>
-    <!-- Big screens -->
-    <div class="navbar navBar1280 languageJS">
-        <div class="categoryTitle">
-            <img class="logo" src="css/img/logo_v4.svg">
-            <div class="version">Playground <span class="versionSub" id="mainTitle1280"></span></div>
-        </div>
+    <body>
+        <!-- Big screens -->
+        <div class="navbar navBar1280 languageJS">
+            <div class="categoryTitle">
+                <img class="logo" src="/css/img/logo_v4.svg">
+                <div class="version">Playground <span class="versionSub" id="mainTitle1280"></span></div>
+            </div>
 
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonJStoTS languageTS" id="toTSbutton1280">Typescript</div>
-            <div class="buttonJStoTS languageJS" id="toJSbutton1280">Javascript</div>
-            <div class="buttonPG run" id="runButton1280"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG" id="newButton1280"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="clearButton1280"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG select" id="menuButton1280"><img src="css/img/optionsButton.svg">
-                <div class="toDisplay languageJS">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub languageJS">
-                            <div class="option selected" id="darkTheme1280">Dark</div>
-                            <div class="option" id="lightTheme1280">Light</div>
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonJStoTS languageTS" id="toTSbutton1280" title="Switch to TypeScript">Typescript</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1280" title="Switch to JavaScript">Javascript</div>
+                <div class="buttonPG run removeOnDiff" id="runButton1280" title="Run&#10;(Alt+Enter)"><img
+                        src="/css/img/playButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="saveButton1280" title="Save&#10;(Ctrl+S)"><img
+                        src="/css/img/saveButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"
+                    title="Download ZIP&#10;(Ctrl+Shift+S)"><img src="/css/img/downloadButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="newButton1280" title="Create new"><img
+                        src="/css/img/newButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280" title="Clear"><img
+                        src="/css/img/clearButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280" title="Compare"><img
+                        src="/css/img/diffButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"
+                    title="Previous difference&#10;(Shift+Alt+F5)"><img src="/css/img/previousButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"
+                    title="Next difference&#10;(Alt+F5)"><img src="/css/img/nextButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280" title="Exit&#10;(Esc)"><img
+                        src="/css/img/exitButton.svg"></div>
+                <div class="buttonPG select removeOnDiff" id="menuButton1280" title="Options"><img
+                        src="/css/img/optionsButton.svg">
+                    <div class="toDisplay languageJS">
+                        <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub languageJS">
+                                <div class="option selected" id="darkTheme1280">Dark</div>
+                                <div class="option" id="lightTheme1280">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub displayFontSize languageJS">
-                            <div class="option">12</div>
-                            <div class="option selected">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub displayFontSize languageJS">
+                                <div class="option">12</div>
+                                <div class="option selected">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option noSubSelect" id="safemodeToggle1280">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option checked noSubSelect" id="editorButton1280">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option noSubSelect" id="fullscreenButton1280">Fullscreen</div>
-                    <div class="option noSubSelect" id="editorFullscreenButton1280">Editor Fullscreen</div>
-                    <div class="option noSubSelect" id="formatButton1280">Format code</div>
-                    <div class="option noSubSelect" id="minimapToggle1280">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option subSelect" id="qrCodeHover1280">QR Code Link <i class="fa fa-chevron-right"
-                            aria-hidden="true"></i>
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImage1280">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="safemodeToggle1280">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option checked noSubSelect" id="editorButton1280">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option noSubSelect" id="fullscreenButton1280">Fullscreen</div>
+                        <div class="option noSubSelect" id="editorFullscreenButton1280">Editor Fullscreen</div>
+                        <div class="option noSubSelect" id="formatButton1280">Format code</div>
+                        <div class="option noSubSelect" id="minimapToggle1280">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option subSelect" id="qrCodeHover1280">QR Code Link <i class="fa fa-chevron-right"
+                                aria-hidden="true"></i>
+                            <div class="toDisplaySub qrCodeImage">
+                                <div class="option" id="qrCodeImage1280">[QR Code Image]</div>
+                            </div>
                         </div>
+                        <div class="option uncheck noSubSelect" id="debugButton1280">Inspector</div>
+                        <div class="option nosubselect" id="metadataButton1280">Metadata</div>
                     </div>
-                    <div class="option uncheck noSubSelect" id="debugButton1280">Inspector</div>
-                    <div class="option nosubselect" id="metadataButton1280">Metadata</div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="buttonPG select">
-                <span id="currentVersion1280"></span>
-                <div class="toDisplay currentVersionDisplay" style="display: none"></div>
+            <div class="category right">
+                <div class="buttonPG select removeOnDiff" title="Select Babylon.js version">
+                    <span id="currentVersion1280"></span>
+                    <div class="toDisplay currentVersionDisplay" style="display: none"></div>
+                </div>
+                <div class="buttonPG select removeOnDiff" title="Examples"><img class="examplesButton"
+                        src="/css/img/examplesButton.svg"></div>
             </div>
-            <div class="buttonPG select"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
-    </div>
 
-    <!-- Mid-size screens -->
-    <div class="navbar navBar1024 languageJS">
-        <div class="categoryTitle">
-            <img class="logo" src="css/img/logo_v4.svg">
-            <div class="version"><span class="versionSub" id="mainTitle1024"></span></div>
-        </div>
+        <!-- Mid-size screens -->
+        <div class="navbar navBar1024 languageJS">
+            <div class="categoryTitle">
+                <img class="logo" src="/css/img/logo_v4.svg">
+                <div class="version"><span class="versionSub" id="mainTitle1024"></span></div>
+            </div>
 
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
-            <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
-            <div class="buttonSpaceKiller"></div>
-            <div class="buttonPG run" id="runButton1024"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG" id="newButton1024"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonJStoTS languageTS" id="toTSbutton1024" title="Switch to TypeScript">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1024" title="Switch to JavaScript">JS</div>
+                <div class="buttonSpaceKiller"></div>
+                <div class="buttonPG run removeOnDiff" id="runButton1024" title="Run&#10;(Alt+Enter)"><img
+                        src="/css/img/playButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="saveButton1024" title="Save&#10;(Ctrl+S)"><img
+                        src="/css/img/saveButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"
+                    title="Download ZIP&#10;(Ctrl+Shift+S)"><img src="/css/img/downloadButton.svg"></div>
+                <div class="buttonPG removeOnDiff" id="newButton1024" title="Create new"><img
+                        src="/css/img/newButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024" title="Clear"><img
+                        src="/css/img/clearButton.svg"></div>
+                <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024" title="Compare"><img
+                        src="/css/img/diffButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img
+                        src="/css/img/previousButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img
+                        src="/css/img/nextButton.svg"></div>
+                <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img
+                        src="/css/img/exitButton.svg"></div>
 
-            <div class="buttonPG select" id="menuButton1024"><img src="css/img/optionsButton.svg">
-                <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                <div class="buttonPG select removeOnDiff" id="menuButton1024" title="Options"><img
+                        src="/css/img/optionsButton.svg">
+                    <div class="toDisplay">
+                        <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
 
-                        <div class="toDisplaySub">
-                            <div class="option selected" id="darkTheme1024">Dark</div>
-                            <div class="option" id="lightTheme1024">Light</div>
+                            <div class="toDisplaySub">
+                                <div class="option selected" id="darkTheme1024">Dark</div>
+                                <div class="option" id="lightTheme1024">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub displayFontSize">
-                            <div class="option">12</div>
-                            <div class="option selected">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option subSelect">Font size <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub displayFontSize">
+                                <div class="option">12</div>
+                                <div class="option selected">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option noSubSelect" id="safemodeToggle1024">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option checked noSubSelect" id="editorButton1024">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option noSubSelect" id="fullscreenButton1024">Fullscreen</div>
-                    <div class="option noSubSelect" id="editorFullscreenButton1024">Editor Fullscreen</div>
-                    <div class="option noSubSelect" id="formatButton1024">Format code</div>
-                    <div class="option noSubSelect" id="minimapToggle1024">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option subSelect" id="qrCodeHover1024">QR Code Link <i class="fa fa-chevron-right"
-                            aria-hidden="true"></i>
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImage1024">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="safemodeToggle1024">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option checked noSubSelect" id="editorButton1024">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
                         </div>
+                        <div class="option noSubSelect" id="fullscreenButton1024">Fullscreen</div>
+                        <div class="option noSubSelect" id="editorFullscreenButton1024">Editor Fullscreen</div>
+                        <div class="option noSubSelect" id="formatButton1024">Format code</div>
+                        <div class="option noSubSelect" id="minimapToggle1024">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option subSelect" id="qrCodeHover1024">QR Code Link <i class="fa fa-chevron-right"
+                                aria-hidden="true"></i>
+                            <div class="toDisplaySub qrCodeImage">
+                                <div class="option" id="qrCodeImage1024">[QR Code Image]</div>
+                            </div>
+                        </div>
+                        <div class="option uncheck noSubSelect" id="debugButton1024">Inspector</div>
+                        <div class="option noSubSelect" id="metadataButton1024">Metadata</div>
                     </div>
-                    <div class="option uncheck noSubSelect" id="debugButton1024">Inspector</div>
-                    <div class="option noSubSelect" id="metadataButton1024">Metadata</div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="buttonPG select">
-                <span id="currentVersion1024"></span>
-                <div class="toDisplay currentVersionDisplay" style="display: none">
+            <div class="category right">
+                <div class="buttonPG select">
+                    <span id="currentVersion1024"></span>
+                    <div class="toDisplay currentVersionDisplay" style="display: none">
+                    </div>
                 </div>
+                <div class="buttonPG select"><img class="examplesButton" src="/css/img/examplesButton.svg"></div>
             </div>
-            <div class="buttonPG select"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
-    </div>
 
-    <!-- Mobile -->
-    <div class="navbar navBarMobile languageJS">
-        <div class="category languageJS" id="JStoTSbar">
-            <div class="buttonPG select" id="menuButtonMobile"><img src="css/img/hamburgerButton.svg">
-                <div class="toDisplay">
-                    <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
-                    <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
-                    <div class="option noSubSelect run" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
-                    <div class="option noSubSelect" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
-                    <div class="option noSubSelect" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download
-                    </div>
-                    <div class="option noSubSelect" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
-                    <div class="option noSubSelect" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear
-                    </div>
-                    <div class="option noSubSelect" id="debugButtonMobile"><img
-                            src="css/img/inspectorButton.svg">Inspector</div>
-                    <div class="option subSelect">
-                        <img src="css/img/optionsButton.svg">
-                        <div id="currentVersionMobile"></div>
-                        <div class="toDisplaySub currentVersionDisplay">
+        <!-- Mobile -->
+        <div class="navbar navBarMobile languageJS">
+            <div class="category languageJS" id="JStoTSbar">
+                <div class="buttonPG select" id="menuButtonMobile"><img src="/css/img/hamburgerButton.svg">
+                    <div class="toDisplay">
+                        <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
+                        <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
+                        <div class="option noSubSelect run" id="runButtonMobile"><img src="/css/img/playButton.svg">Run
                         </div>
-                    </div>
-                    <div class="option subSelect"><img src="css/img/optionsButton.svg">Theme
-                        <div class="toDisplaySub">
-                            <div class="option selected" id="darkThemeMobile">Dark</div>
-                            <div class="option" id="lightThemeMobile">Light</div>
+                        <div class="option noSubSelect" id="saveButtonMobile"><img src="/css/img/saveButton.svg">Save
                         </div>
-                    </div>
-                    <div class="option subSelect"><img src="css/img/optionsButton.svg">Font size
-                        <div class="toDisplaySub displayFontSize">
-                            <div class="option">8</div>
-                            <div class="option">10</div>
-                            <div class="option selected">12</div>
-                            <div class="option">14</div>
-                            <div class="option">16</div>
-                            <div class="option">18</div>
-                            <div class="option">20</div>
-                            <div class="option">22</div>
+                        <div class="option noSubSelect" id="zipButtonMobile"><img
+                                src="/css/img/downloadButton.svg">Download
                         </div>
-                    </div>
-                    <div style="display: none;" class="option noSubSelect" id="safemodeToggleMobile">Safe mode
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <div style="display: none;" class="option checked noSubSelect" id="editorButtonMobile">Editor
-                        <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div style="display: none;" class="option nosubselect" id="fullscreenButtonMobile"
-                        style="display: none">Fullscreen</div>
-                    <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
-                        style="display: none">Editor
-                        Fullscreen</div>
-                    <div class="option nosubselect" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
-                        code</div>
-                    <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
-                        <i class="fa fa-square" aria-hidden="true"></i>
-                    </div>
-                    <!-- <div class="option subSelect" id="qrCodeHoverMobile"><img src="css/img/optionsButton.svg">QR Code Link
-                        <div class="toDisplaySub qrCodeImage">
-                            <div class="option" id="qrCodeImageMobile">[QR Code Image]</div>
+                        <div class="option noSubSelect" id="newButtonMobile"><img src="/css/img/newButton.svg">New</div>
+                        <div class="option noSubSelect" id="clearButtonMobile"><img src="/css/img/clearButton.svg">Clear
                         </div>
-                    </div> -->
-                    <div class="option nosubselect" id="metadataButtonMobile"><img
-                            src="css/img/metadataButton.svg">Metadata</div>
-                    <div class="option nosubselect"><img class="examplesButton"
-                            src="css/img/examplesButton.svg">Examples</div>
-                    <div class="option subSelect"><img src="css/img/examplesButton.svg">Links / Tools
-                        <div class="toDisplaySub displayFooterLinks">
-                            <div class="option link">
-                                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
-                            </div>
-                            <div class="option link">
-                                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                        <div class="option noSubSelect" id="debugButtonMobile"><img
+                                src="/css/img/inspectorButton.svg">Inspector</div>
+                        <div class="option subSelect">
+                            <img src="/css/img/optionsButton.svg">
+                            <div id="currentVersionMobile"></div>
+                            <div class="toDisplaySub currentVersionDisplay">
                             </div>
-                            <div class="option link">
-                                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                        </div>
+                        <div class="option subSelect"><img src="/css/img/optionsButton.svg">Theme
+                            <div class="toDisplaySub">
+                                <div class="option selected" id="darkThemeMobile">Dark</div>
+                                <div class="option" id="lightThemeMobile">Light</div>
                             </div>
-                            <div class="option link">
-                                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                        </div>
+                        <div class="option subSelect"><img src="/css/img/optionsButton.svg">Font size
+                            <div class="toDisplaySub displayFontSize">
+                                <div class="option">8</div>
+                                <div class="option">10</div>
+                                <div class="option selected">12</div>
+                                <div class="option">14</div>
+                                <div class="option">16</div>
+                                <div class="option">18</div>
+                                <div class="option">20</div>
+                                <div class="option">22</div>
                             </div>
-                            <div class="option link">
-                                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                        </div>
+                        <div style="display: none;" class="option noSubSelect" id="safemodeToggleMobile">Safe mode
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <div style="display: none;" class="option checked noSubSelect" id="editorButtonMobile">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div style="display: none;" class="option nosubselect" id="fullscreenButtonMobile"
+                            style="display: none">Fullscreen</div>
+                        <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
+                            style="display: none">Editor
+                            Fullscreen</div>
+                        <div class="option nosubselect" id="formatButtonMobile"><img
+                                src="/css/img/optionsButton.svg">Format
+                            code</div>
+                        <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
+                            <i class="fa fa-square" aria-hidden="true"></i>
+                        </div>
+                        <!-- <div class="option subSelect" id="qrCodeHoverMobile"><img src="/css/img/optionsButton.svg">QR Code Link
+                        <div class="toDisplaySub qrCodeImage">
+                            <div class="option" id="qrCodeImageMobile">[QR Code Image]</div>
+                        </div>
+                    </div> -->
+                        <div class="option nosubselect" id="metadataButtonMobile"><img
+                                src="/css/img/metadataButton.svg">Metadata</div>
+                        <div class="option nosubselect"><img class="examplesButton"
+                                src="/css/img/examplesButton.svg">Examples</div>
+                        <div class="option subSelect"><img src="/css/img/examplesButton.svg">Links / Tools
+                            <div class="toDisplaySub displayFooterLinks">
+                                <div class="option link">
+                                    <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                                </div>
+                                <div class="option link">
+                                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                                </div>
                             </div>
                         </div>
                     </div>
                 </div>
+                <div class="categoryTitle">
+                    <img class="logo" src="/css/img/logo_v4.svg">
+                    <div class="version"><span class="versionSub" id="mainTitleMobile"></span></div>
+                </div>
             </div>
-            <div class="categoryTitle">
-                <img class="logo" src="css/img/logo_v4.svg">
-                <div class="version"><span class="versionSub" id="mainTitleMobile"></span></div>
-            </div>
-        </div>
 
-        <div id="switchWrapper" class="languageJS">
-            <img id="switchWrapperCode" src="css/img/codeButton.svg">
-            <img id="switchWrapperCanvas" src="css/img/canvas3Dbutton.svg">
+            <div id="switchWrapper" class="languageJS">
+                <img id="switchWrapperCode" src="/css/img/codeButton.svg">
+                <img id="switchWrapperCanvas" src="/css/img/canvas3Dbutton.svg">
+            </div>
         </div>
-    </div>
 
-    <!-- Common things -->
+        <!-- Common things -->
 
-    <div class="wrapper">
-        <div id="jsEditor"></div>
-        <div id="canvasZone">
-            <canvas touch-action="none" id="renderCanvas"></canvas>
+        <div class="wrapper">
+            <div id="jsEditor"></div>
+            <div id="canvasZone">
+                <canvas touch-action="none" id="renderCanvas"></canvas>
+            </div>
         </div>
-    </div>
-    <div id="exampleList" class="javascript">
-        <div id="exampleBanner" class="languageJS">
-            <h1>Examples<img id="examplesButtonClose" src="css/img/clearButton.svg"></h1>
+        <div id="exampleList" class="javascript">
+            <div id="exampleBanner" class="languageJS">
+                <h1>Examples<img id="examplesButtonClose" src="/css/img/clearButton.svg"></h1>
+            </div>
+            <div class="horizontalSeparator"></div>
+            <input id="filterBar" type="text" placeholder="Filter examples...">
+            <img id="filterBarClear"
+                src="/css/img/clear_button.png">
         </div>
-        <div class="horizontalSeparator"></div>
-        <input id="filterBar" type="text" placeholder="Filter examples...">
-        <img id="filterBarClear"
-            src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
-    </div>
 
-    <div class="fpsLabel languageJS" id="fpsLabel"></div>
+        <div class="fpsLabel languageJS" id="fpsLabel"></div>
 
-    <div id="errorZone">
-    </div>
+        <div id="errorZone">
+        </div>
 
-    <div class="navbarBottom">
-        <div id="statusBar"></div>
-        <div class="links">
-            <div class='link'>
-                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+        <div class="navbarBottom">
+            <div id="statusBar"></div>
+            <div class="links">
+                <div class='link'>
+                    <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div id="saveLayer" class="save-layer">
-        <div class="save-form languageJS ">
-            <img id="saveFormButtonClose" src="css/img/clearButton.svg">
-            <label for="saveFormTitle">TITLE</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+        <div id="saveLayer" class="save-layer">
+            <div class="save-form languageJS ">
+                <img id="saveFormButtonClose" src="/css/img/clearButton.svg">
+                <label for="saveFormTitle">TITLE</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
 
-            <label for="saveFormDescription">DESCRIPTION</label>
-            <div class="separator"></div>
-            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+                <label for="saveFormDescription">DESCRIPTION</label>
+                <div class="separator"></div>
+                <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
 
-            <label for="saveFormTags">TAGS (separated by comma)</label>
-            <div class="separator"></div>
-            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+                <label for="saveFormTags">TAGS (separated by comma)</label>
+                <div class="separator"></div>
+                <textarea id="saveFormTags" rows="4" cols="10"></textarea>
 
-            <div class="save-form-buttons" id="saveFormButtons">
-                <div id="saveFormButtonOk">OK</div>
-                <div id="saveFormButtonCancel">Cancel</div>
+                <div class="save-form-buttons" id="saveFormButtons">
+                    <div id="saveFormButtonOk">OK</div>
+                    <div id="saveFormButtonCancel">Cancel</div>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div id="waitDiv">
-        <div id="logo-part">
-            <img src="css/img/v4.svg" id="waitLogo" />
-            <img src="css/img/spinner.svg" id="waitSpinner" />
+        <div id="waitDiv">
+            <div id="logo-part">
+                <img src="/css/img/v4.svg" id="waitLogo" />
+                <img src="/css/img/spinner.svg" id="waitSpinner" />
+            </div>
         </div>
-    </div>
 
-    <!-- jQuery -->
-    <script src="js/libs/jquery.min.js"></script>
-    <script src="js/jquery.qrcode.js"></script>
-    <script src="js/qrcode.js"></script>
+        <!-- jQuery -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+        <script src="https://rawcdn.githack.com/jeromeetienne/jquery-qrcode/master/jquery.qrcode.min.js"></script>
 
-    <!-- Main scripts -->
-    <script src="js/config_versions.js"></script>
-    <script src="js/pbt.js"></script>
-    <script src="js/libs/typescript.js"></script>
-    <script src="js/examples.js"></script>
-    <!-- <script src="js/main.js"></script> -->
-    <script src="js/mainWebGPU.js"></script>
-    <script src="js/menuPG.js"></script>
-    <script src="js/monacoCreator.js"></script>
-    <script src="js/settingsPG.js"></script>
-    <script src="js/utils.js"></script>
-    <script src="js/zipTool.js"></script>
-    <script src="js/index.js"></script>
-</body>
+        <!-- Main scripts -->
+        <script src="/js/config_versions.js"></script>
+        <script src="/js/libs/typescript.js"></script>
+        <script src="/js/examples.js"></script>
+        <!-- <script src="/js/main.js"></script> -->
+        <script src="/js/mainWebGPU.js"></script>
+        <script src="/js/menuPG.js"></script>
+        <script src="/js/monacoCreator.js"></script>
+        <script src="/js/settingsPG.js"></script>
+        <script src="/js/utils.js"></script>
+        <script src="/js/zipTool.js"></script>
+        <script src="/js/index.js"></script>
+    </body>
 
 </html>

+ 10 - 0
Playground/js/config_versions.js

@@ -10,6 +10,16 @@ CONFIG_last_versions = [
         "https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js",
         "https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"
     ]],
+    ["4.1.0", [
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.1.0/dist/babylon.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.1.0/dist/gui/babylon.gui.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.1.0/dist/inspector/babylon.inspector.bundle.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.1.0/dist/materialsLibrary/babylonjs.materials.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.1.0/dist/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.1.0/dist/postProcessesLibrary/babylonjs.postProcess.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.1.0/dist/loaders/babylonjs.loaders.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.1.0/dist/serializers/babylonjs.serializers.min.js"
+    ]],
     ["4.0.3", [
         "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.0.3/dist/babylon.js",
         "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.0.3/dist/gui/babylon.gui.min.js",

+ 13 - 1
Playground/js/definitionWorker.js

@@ -1,3 +1,14 @@
+// > This worker will analyze the syntaxtree and return an array of deprecated functions (but the goal is to do more in the future!)
+// We need to do this because:
+// - checking extended properties during completion is time consuming, so we need to prefilter potential candidates
+// - we don't want to maintain a static list of deprecated members or to instrument this work on the CI
+// - we have more plans involving syntaxtree analysis
+// > This worker was carefully crafted to work even if the processing is super fast or super long. 
+// In both cases the deprecation filter will start working after the worker is done.
+// We will also need this worker in the future to compute Intellicode scores for completion using dedicated attributes.
+
+// see monacoCreator.js/setupDefinitionWorker
+
 // monaco is using 'define' for module dependencies and service lookup.
 // hopefully typescript is self-contained
 var ts = null;
@@ -8,6 +19,7 @@ importScripts("../node_modules/monaco-editor/dev/vs/language/typescript/lib/type
 // store deprecated names
 var deprecatedCandidates = [];
 
+// optimize syntaxtree visitor, we don't care about non documented nodes
 function canHaveJsDoc(node) {
     const kind = node.kind;
     switch (kind) {
@@ -95,4 +107,4 @@ function processDefinition(code) {
 self.addEventListener('message', event => {
     const { code } = event.data;
     processDefinition(code);
-});
+});

+ 86 - 5
Playground/js/examples.js

@@ -79,12 +79,94 @@ class Examples {
     displayExamples() {
         this.parent.menuPG.removeAllOptions();
 
+        var scripts = this.parent.main.scripts;
+
+        if (!this.examplesLoaded) {
+
+            
+            function sortScriptsList(a, b) {
+                if (a.title < b.title) return -1;
+                else return 1;
+            }
+
+            for (var i = 0; i < scripts.length; i++) {
+                scripts[i].samples.sort(sortScriptsList);
+
+                var exampleCategory = document.createElement("div");
+                exampleCategory.classList.add("categoryContainer");
+
+                var exampleCategoryTitle = document.createElement("p");
+                exampleCategoryTitle.innerText = scripts[i].title;
+                exampleCategory.appendChild(exampleCategoryTitle);
+
+                for (var ii = 0; ii < scripts[i].samples.length; ii++) {
+                    var example = document.createElement("div");
+                    example.classList.add("itemLine");
+                    example.id = ii;
+
+                    var exampleImg = document.createElement("img");
+                    exampleImg.setAttribute("data-src", scripts[i].samples[ii].icon.replace("icons", "https://doc.babylonjs.com/examples/icons"));
+                    exampleImg.setAttribute("onClick", "document.getElementById('PGLink_" + scripts[i].samples[ii].PGID + "').click();");
+
+                    var exampleContent = document.createElement("div");
+                    exampleContent.classList.add("itemContent");
+                    exampleContent.setAttribute("onClick", "document.getElementById('PGLink_" + scripts[i].samples[ii].PGID + "').click();");
+
+                    var exampleContentLink = document.createElement("div");
+                    exampleContentLink.classList.add("itemContentLink");
+
+                    var exampleTitle = document.createElement("h3");
+                    exampleTitle.classList.add("exampleCategoryTitle");
+                    exampleTitle.innerText = scripts[i].samples[ii].title;
+                    var exampleDescr = document.createElement("div");
+                    exampleDescr.classList.add("itemLineChild");
+                    exampleDescr.innerText = scripts[i].samples[ii].description;
+
+                    var exampleDocLink = document.createElement("a");
+                    exampleDocLink.classList.add("itemLineDocLink");
+                    exampleDocLink.innerText = "Documentation";
+                    exampleDocLink.href = scripts[i].samples[ii].doc;
+                    exampleDocLink.target = "_blank";
+
+                    var examplePGLink = document.createElement("a");
+                    examplePGLink.id = "PGLink_" + scripts[i].samples[ii].PGID;
+                    examplePGLink.classList.add("itemLinePGLink");
+                    examplePGLink.innerText = "Display";
+                    examplePGLink.href = scripts[i].samples[ii].PGID;
+                    examplePGLink.addEventListener("click", function () {
+                        location.href = this.href;
+                        location.reload();
+                    });
+
+                    exampleContentLink.appendChild(exampleTitle);
+                    exampleContentLink.appendChild(exampleDescr);
+                    exampleContent.appendChild(exampleContentLink);
+                    exampleContent.appendChild(exampleDocLink);
+                    exampleContent.appendChild(examplePGLink);
+
+                    example.appendChild(exampleImg);
+                    example.appendChild(exampleContent);
+
+                    exampleCategory.appendChild(example);
+                }
+
+                exampleList.appendChild(exampleCategory);
+            }
+        }
+        this.examplesLoaded = true;
+
+
         this.isExamplesDisplayed = true;
         this.exampleList.style.display = 'block';
         document.getElementsByClassName('wrapper')[0].style.width = 'calc(100% - 400px)';
 
         this.fpsLabel.style.display = 'none';
         this.toggleExamplesButtons.call(this, true);
+        this.exampleList.querySelectorAll("img").forEach(function (img) {
+            if (!img.src) {
+                img.src = img.getAttribute("data-src");
+            }
+        })
     };
 
     /**
@@ -94,20 +176,19 @@ class Examples {
         this.isExamplesDisplayed = false;
         this.exampleList.style.display = 'none';
         document.getElementsByClassName('wrapper')[0].style.width = '100%';
-        
-        if(this.parent.menuPG && this.parent.menuPG.isMobileVersion && document.getElementById('jsEditor').style.display == 'block') {}
-        else this.fpsLabel.style.display = 'block';
+
+        if (this.parent.menuPG && this.parent.menuPG.isMobileVersion && document.getElementById('jsEditor').style.display == 'block') {} else this.fpsLabel.style.display = 'block';
         this.toggleExamplesButtons.call(this, false);
     };
 
     toggleExamplesButtons(selected) {
         if (this.examplesButtons.length > 0) {
             for (var i = 0; i < this.examplesButtons.length; i++) {
-                if(selected)
+                if (selected)
                     this.examplesButtons[i].parentElement.classList.add("selected");
                 else
                     this.examplesButtons[i].parentElement.classList.remove("selected");
             }
         }
     };
-}
+}

+ 62 - 17
Playground/js/frame.js

@@ -1,9 +1,8 @@
-
-var engine = null;
+var engine = null;
 var canvas = null;
 var scene = null;
 
-fastEval = function(code) {
+fastEval = function (code) {
     var head = document.getElementsByTagName('head')[0];
     var script = document.createElement('script');
     script.setAttribute('type', 'text/javascript');
@@ -16,11 +15,11 @@ fastEval = function(code) {
     head.appendChild(script);
 }
 
-handleException = function(e) {
+handleException = function (e) {
     console.error(e);
 }
 
-run = function() {
+run = function () {
     var snippetUrl = "https://snippet.babylonjs.com";
     var fpsLabel = document.getElementById("fpsLabel");
     var refreshAnchor = document.getElementById("refresh");
@@ -40,7 +39,7 @@ run = function() {
 
     BABYLON.Engine.ShadersRepository = "/src/Shaders/";
 
-    compileAndRun = function(code) {
+    compileAndRun = function (code) {
         try {
 
             if (!BABYLON.Engine.isSupported()) {
@@ -56,7 +55,10 @@ run = function() {
             canvas = document.getElementById("renderCanvas");
 
             createDefaultEngine = function () {
-                return new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
+                return new BABYLON.Engine(canvas, true, {
+                    preserveDrawingBuffer: true,
+                    stencil: true
+                });
             }
 
             if (code.indexOf("createEngine") !== -1) {
@@ -116,22 +118,25 @@ run = function() {
                 if (scene.activeCamera || scene.activeCameras.length > 0) {
                     scene.render();
                 }
-
-                fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
-            }.bind(this));         
+                if (fpsLabel && !(scene.activeCamera && 
+                    scene.activeCamera.getClassName && 
+                    scene.activeCamera.getClassName() === 'WebXRCamera')) {
+                    fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
+                }
+            }.bind(this));
 
         } catch (e) {
             // showError(e.message);
         }
     };
-    window.addEventListener("resize", function() {
+    window.addEventListener("resize", function () {
         if (engine) {
             engine.resize();
         }
     });
 
     // UI
-    var cleanHash = function() {
+    var cleanHash = function () {
         var splits = decodeURIComponent(location.hash.substr(1)).split("#");
 
         if (splits.length > 2) {
@@ -141,22 +146,37 @@ run = function() {
         location.hash = splits.join("#");
     };
 
-    var checkHash = function() {
+    var checkHash = function () {
         if (location.hash) {
             cleanHash();
 
             try {
                 var xmlHttp = new XMLHttpRequest();
-                xmlHttp.onreadystatechange = function() {
+                xmlHttp.onreadystatechange = function () {
                     if (xmlHttp.readyState === 4) {
                         if (xmlHttp.status === 200) {
-                            var snippetCode = JSON.parse(JSON.parse(xmlHttp.responseText).jsonPayload).code;
+                            var snippet = JSON.parse(xmlHttp.responseText);
+                            var snippetCode = JSON.parse(snippet.jsonPayload).code;
                             compileAndRun(snippetCode);
 
                             var refresh = document.getElementById("refresh");
 
+                            if (snippet.name != null && snippet.name != "") {
+                                this.currentSnippetTitle = snippet.name;
+                            } else this.currentSnippetTitle = null;
+    
+                            if (snippet.description != null && snippet.description != "") {
+                                this.currentSnippetDescription = snippet.description;
+                            } else this.currentSnippetDescription = null;
+    
+                            if (snippet.tags != null && snippet.tags != "") {
+                                this.currentSnippetTags = snippet.tags;
+                            } else this.currentSnippetTags = null;
+
+                            updateMetadata.call(this);
+
                             if (refresh) {
-                                refresh.addEventListener("click", function() {
+                                refresh.addEventListener("click", function () {
                                     compileAndRun(snippetCode);
                                 });
                             }
@@ -182,8 +202,33 @@ run = function() {
         }
     };
 
+    var updateMetadata = function() {
+        var selection;
+
+        if (this.currentSnippetTitle) {
+            selection = document.querySelector('title');
+            if (selection) {
+                selection.innerText = (this.currentSnippetTitle + " | Babylon.js Playground");
+            }
+        }
+
+        if (this.currentSnippetDescription) {
+            selection = document.querySelector('meta[name="description"]');
+            if (selection) {
+                selection.setAttribute("content", this.currentSnippetDescription + " - Babylon.js Playground");
+            }
+        }
+
+        if (this.currentSnippetTags) {
+            selection = document.querySelector('meta[name="keywords"]');
+            if (selection) {
+                selection.setAttribute("content", "babylon.js, game engine, webgl, 3d," + this.currentSnippetTags);
+            }
+        }
+    }
+
     checkHash();
 
 }
 
-run();
+run();

+ 1 - 1
Playground/js/index.js

@@ -12,7 +12,7 @@
         /**
          * View split
          */
-        this.splitInstance = Split(['#jsEditor', '#canvasZone']);
+        this.splitInstance = Split(['#jsEditor', '#canvasZone'], {minSize: 0});
 
         /**
          * Run the main script

+ 0 - 89
Playground/js/jquery.qrcode.js

@@ -1,89 +0,0 @@
-(function( $ ){
-	$.fn.qrcode = function(options) {
-		// if options is string, 
-		if( typeof options === 'string' ){
-			options	= { text: options };
-		}
-
-		// set default values
-		// typeNumber < 1 for automatic calculation
-		options	= $.extend( {}, {
-			render		: "canvas",
-			width		: 256,
-			height		: 256,
-			typeNumber	: -1,
-			correctLevel	: QRErrorCorrectLevel.H,
-                        background      : "#ffffff",
-                        foreground      : "#000000"
-		}, options);
-
-		var createCanvas	= function(){
-			// create the qrcode itself
-			var qrcode	= new QRCode(options.typeNumber, options.correctLevel);
-			qrcode.addData(options.text);
-			qrcode.make();
-
-			// create canvas element
-			var canvas	= document.createElement('canvas');
-			canvas.width	= options.width;
-			canvas.height	= options.height;
-			var ctx		= canvas.getContext('2d');
-
-			// compute tileW/tileH based on options.width/options.height
-			var tileW	= options.width  / qrcode.getModuleCount();
-			var tileH	= options.height / qrcode.getModuleCount();
-
-			// draw in the canvas
-			for( var row = 0; row < qrcode.getModuleCount(); row++ ){
-				for( var col = 0; col < qrcode.getModuleCount(); col++ ){
-					ctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background;
-					var w = (Math.ceil((col+1)*tileW) - Math.floor(col*tileW));
-					var h = (Math.ceil((row+1)*tileW) - Math.floor(row*tileW));
-					ctx.fillRect(Math.round(col*tileW),Math.round(row*tileH), w, h);  
-				}	
-			}
-			// return just built canvas
-			return canvas;
-		}
-
-		// from Jon-Carlos Rivera (https://github.com/imbcmdth)
-		var createTable	= function(){
-			// create the qrcode itself
-			var qrcode	= new QRCode(options.typeNumber, options.correctLevel);
-			qrcode.addData(options.text);
-			qrcode.make();
-			
-			// create table element
-			var $table	= $('<table></table>')
-				.css("width", options.width+"px")
-				.css("height", options.height+"px")
-				.css("border", "0px")
-				.css("border-collapse", "collapse")
-				.css('background-color', options.background);
-		  
-			// compute tileS percentage
-			var tileW	= options.width / qrcode.getModuleCount();
-			var tileH	= options.height / qrcode.getModuleCount();
-
-			// draw in the table
-			for(var row = 0; row < qrcode.getModuleCount(); row++ ){
-				var $row = $('<tr></tr>').css('height', tileH+"px").appendTo($table);
-				
-				for(var col = 0; col < qrcode.getModuleCount(); col++ ){
-					$('<td></td>')
-						.css('width', tileW+"px")
-						.css('background-color', qrcode.isDark(row, col) ? options.foreground : options.background)
-						.appendTo($row);
-				}	
-			}
-			// return just built canvas
-			return $table;
-		}
-  
-
-		return this.each(function(){
-			var element	= options.render == "canvas" ? createCanvas() : createTable();
-			jQuery(element).appendTo(this);
-		});
-	};
-})( jQuery );

File diff suppressed because it is too large
+ 442 - 284
Playground/js/main.js


+ 36 - 6
Playground/js/mainWebGPU.js

@@ -153,7 +153,12 @@ compileAndRun = function(parent, fpsLabel) {
                         scene.render();
                     }
 
-                    fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
+                    // Update FPS if camera is not a webxr camera
+                    if(!(scene.activeCamera && 
+                        scene.activeCamera.getClassName && 
+                        scene.activeCamera.getClassName() === 'WebXRCamera')) {
+                        fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
+                    }
                 }.bind(this));
 
                 if (checkSceneCount && engine.scenes.length === 0) {
@@ -262,11 +267,14 @@ class Main {
         this.loadScriptsList(restoreVersionResult);
 
         // -------------------- UI --------------------
+        var handleRun = () => compileAndRun(this.parent, this.fpsLabel);
+        var handleSave = () => this.askForSave();
+        var handleGetZip = () => this.parent.zipTool.getZip(engine);
 
         // Display BJS version
         if (BABYLON) this.parent.utils.setToMultipleID("mainTitle", "innerHTML", "v" + BABYLON.Engine.Version);
         // Run
-        this.parent.utils.setToMultipleID("runButton", "click", () => compileAndRun(this.parent, this.fpsLabel));
+        this.parent.utils.setToMultipleID("runButton", "click", handleRun);
         // New
         this.parent.utils.setToMultipleID("newButton", "click", function () {
             this.parent.menuPG.removeAllOptions();
@@ -278,11 +286,9 @@ class Main {
             this.clear.call(this);
         }.bind(this));
         // Save
-        this.parent.utils.setToMultipleID("saveButton", "click", this.askForSave.bind(this));
+        this.parent.utils.setToMultipleID("saveButton", "click", handleSave);
         // Zip
-        this.parent.utils.setToMultipleID("zipButton", "click", function () {
-            this.parent.zipTool.getZip(engine);
-        }.bind(this));
+        this.parent.utils.setToMultipleID("zipButton", "click", handleGetZip);
         // Themes
         this.parent.utils.setToMultipleID("darkTheme", "click", function () {
             this.parent.menuPG.removeAllOptions();
@@ -410,6 +416,30 @@ class Main {
         this.parent.settingsPG.setScriptLanguage();
         // Check if it's mobile mode. If true, switch to full canvas by default
         this.parent.menuPG.resizeBigCanvas();
+
+        // HotKeys
+        document.onkeydown = function (e) {
+            // Alt+Enter to Run
+            if (e.altKey && (e.key === 'Enter' || event.which === 13)) {
+                handleRun();
+            }
+            // Ctrl+Shift+S to Download Zip
+            else if (
+              (window.navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) &&
+              e.shiftKey &&
+              (e.key === 'S' || event.which === 83)
+            ) {
+                handleGetZip();
+            }
+            // Ctrl+S to Save
+            else if (
+              (window.navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) &&
+              (e.key === 'S' || event.which === 83)
+            ) {
+                e.preventDefault();
+                handleSave();
+            }
+        };
     };
 
     /**

+ 172 - 21
Playground/js/monacoCreator.js

@@ -1,5 +1,14 @@
 /**
  * This JS file is for Monaco management
+ * This file is quite technical, please make sure that you understand all parts before making changes.
+ * Please also make sure that the following is still working before submitting a PR:
+ * - autocompletion.
+ * - deprecated members marking.
+ * - compilation and proper error reporting for both JS and TS.
+ * - private/internal member filtering (we should not see members starting with an underscore).
+ * - dedicated adornments, like the one used for previewing colors for BABYLON.ColorX types.
+ * - diff support.
+ * - minimap support.
  */
 class MonacoCreator {
     constructor(parent) {
@@ -12,8 +21,28 @@ class MonacoCreator {
         this.blockEditorChange = false;
         this.definitionWorker = null;
         this.deprecatedCandidates = [];
+        this.templates = [];
 
         this.compilerTriggerTimeoutID = null;
+
+        this.addOnMonacoLoadedCallback(
+            function () {
+                this.parent.main.run();
+
+                // Register a global observable for inspector to request code changes
+                window.Playground = {
+                    onRequestCodeChangeObservable: new BABYLON.Observable()
+                }
+
+                window.Playground.onRequestCodeChangeObservable.add((options) => {
+                    let code = this.getCode();
+                    code = code.replace(options.regex, options.replace);
+
+                    this.setCode(code);
+                });
+            },
+            this
+        );
     }
 
     // ACCESSORS
@@ -34,8 +63,8 @@ class MonacoCreator {
         return this.monacoMode;
     };
     set MonacoMode(mode) {
-        if (this.monacoMode != "javascript"
-            && this.monacoMode != "typescript")
+        if (this.monacoMode != "javascript" &&
+            this.monacoMode != "typescript")
             console.warn("Error while defining Monaco Mode");
         this.monacoMode = mode;
     };
@@ -49,10 +78,24 @@ class MonacoCreator {
 
     // FUNCTIONS
 
+    waitForDefine() {
+        return new Promise(function (resolve, reject) {
+            function timeout() {
+                if (!window.define) {
+                    setTimeout(timeout, 200);
+                } else {
+                    resolve();
+                }
+            }
+            timeout();
+        });
+    }
+
     /**
      * Load the Monaco Node module.
      */
     async loadMonaco(typings) {
+        await this.waitForDefine();
         let response = await fetch(typings || "https://preview.babylonjs.com/babylon.d.ts");
         if (!response.ok) {
             return;
@@ -71,42 +114,107 @@ class MonacoCreator {
 
         this.setupDefinitionWorker(libContent);
 
-        require.config({ paths: { 'vs': 'node_modules/monaco-editor/dev/vs' } });
+        // Load code templates
+        response = await fetch("/templates.json");
+        if (response.ok) {
+            this.templates = await response.json();
+        }
+
+        // WARNING !!! We need the 'dev' version of Monaco, as we use monkey-patching to hook into the suggestion adapter
+        require.config({
+            paths: {
+                'vs': '/node_modules/monaco-editor/dev/vs'
+            }
+        });
 
         require(['vs/editor/editor.main'], () => {
+            // Setup the Monaco compilation pipeline, so we can reuse it directly for our scrpting needs
             this.setupMonacoCompilationPipeline(libContent);
+
+            // This is used for a vscode-like color preview for ColorX types
             this.setupMonacoColorProvider();
 
+            // enhance templates with extra properties
+            for (const template of this.templates) {
+                template.kind = monaco.languages.CompletionItemKind.Snippet,
+                template.sortText = "!" + template.label; // make sure templates are on top of the completion window
+                template.insertTextRules = monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet;
+            }
+
+            // As explained above, we need the 'dev' version of Monaco to access this adapter!
             require(['vs/language/typescript/languageFeatures'], module => {
                 this.hookMonacoCompletionProvider(module.SuggestAdapter);
             });
 
-            this.parent.main.run();
+            this.onMonacoLoaded();
         });
     };
 
+    onMonacoLoaded() {
+        if (this.monacoLoaded) {
+            return;
+        }
+        this.onMonacoLoadedCallbacks.forEach((callbackDef) => {
+            callbackDef.func.call(callbackDef.context, this);
+        });
+        this.monacoLoaded = true;
+    }
+
+    /**
+     * This will register a new callback that will be triggered when the monaco loader is done.
+     * If the loader is already done, the function will be executed right away. 
+     * @param {Function} func the function to call when monaco is available
+     * @param {*} context The context of this function
+     */
+    addOnMonacoLoadedCallback(func, context) {
+        this.onMonacoLoadedCallbacks = this.onMonacoLoadedCallbacks || [];
+        if (this.monacoLoaded) {
+            func.call(context, this);
+        } else {
+            this.onMonacoLoadedCallbacks.push({
+                func: func,
+                context: context
+            });
+        }
+    }
+
+    // > This worker will analyze the syntaxtree and return an array of deprecated functions (but the goal is to do more in the future!)
+    // We need to do this because:
+    // - checking extended properties during completion is time consuming, so we need to prefilter potential candidates
+    // - we don't want to maintain a static list of deprecated members or to instrument this work on the CI
+    // - we have more plans involving syntaxtree analysis
+    // > This worker was carefully crafted to work even if the processing is super fast or super long. 
+    // In both cases the deprecation filter will start working after the worker is done.
+    // We will also need this worker in the future to compute Intellicode scores for completion using dedicated attributes.
     setupDefinitionWorker(libContent) {
-        this.definitionWorker = new Worker('js/definitionWorker.js');
-        this.definitionWorker.addEventListener('message', ({ data }) => {
+        this.definitionWorker = new Worker('/js/definitionWorker.js');
+        this.definitionWorker.addEventListener('message', ({
+            data
+        }) => {
             this.deprecatedCandidates = data.result;
             this.analyzeCode();
         });
-        this.definitionWorker.postMessage({ code: libContent });
+        this.definitionWorker.postMessage({
+            code: libContent
+        });
     }
 
     isDeprecatedEntry(details) {
-        return details
-            && details.tags
-            && details.tags.find(this.isDeprecatedTag);
+        return details &&
+            details.tags &&
+            details.tags.find(this.isDeprecatedTag);
     }
 
     isDeprecatedTag(tag) {
-        return tag
-            && tag.name == "deprecated";
+        return tag &&
+            tag.name == "deprecated";
     }
 
+    // This will make sure that all members marked with a deprecated jsdoc attribute will be marked as such in Monaco UI
+    // We use a prefiltered list of deprecated candidates, because the effective call to getCompletionEntryDetails is slow.
+    // @see setupDefinitionWorker
     async analyzeCode() {
-        // if the definition worker is very fast, this can be called out of context
+        // if the definition worker is very fast, this can be called out of context. @see setupDefinitionWorker
         if (!this.jsEditor)
             return;
 
@@ -131,7 +239,10 @@ class MonacoCreator {
         for (const candidate of this.deprecatedCandidates) {
             const matches = model.findMatches(candidate, null, false, true, null, false);
             for (const match of matches) {
-                const position = { lineNumber: match.range.startLineNumber, column: match.range.startColumn };
+                const position = {
+                    lineNumber: match.range.startLineNumber,
+                    column: match.range.startColumn
+                };
                 const wordInfo = model.getWordAtPosition(position);
                 const offset = model.getOffsetAt(position);
 
@@ -140,6 +251,7 @@ class MonacoCreator {
                     continue;
 
                 // the following is time consuming on all suggestions, that's why we precompute deprecated candidate names in the definition worker to filter calls
+                // @see setupDefinitionWorker
                 const details = await languageService.getCompletionEntryDetails(uri.toString(), offset, wordInfo.word);
                 if (this.isDeprecatedEntry(details)) {
                     const deprecatedInfo = details.tags.find(this.isDeprecatedTag);
@@ -159,6 +271,9 @@ class MonacoCreator {
         monaco.editor.setModelMarkers(model, source, markers);
     }
 
+    // This is our hook in the Monaco suggest adapter, we are called everytime a completion UI is displayed
+    // So we need to be super fast.
+    // We need the 'dev' version of Monaco, as we use monkey-patching to hook into this suggestion adapter
     hookMonacoCompletionProvider(provider) {
         const provideCompletionItems = provider.prototype.provideCompletionItems;
         const owner = this;
@@ -176,6 +291,7 @@ class MonacoCreator {
                 if (owner.deprecatedCandidates.includes(suggestion.label)) {
 
                     // the following is time consuming on all suggestions, that's why we precompute deprecated candidate names in the definition worker to filter calls
+                    // @see setupDefinitionWorker
                     const uri = suggestion.uri;
                     const worker = await this._worker(uri);
                     const model = monaco.editor.getModel(uri);
@@ -187,6 +303,17 @@ class MonacoCreator {
                 }
             }
 
+            // add our own templates when invoked without context
+            if (context.triggerKind == monaco.languages.CompletionTriggerKind.Invoke) {
+                for (const template of owner.templates) {
+                    if (template.language && owner.monacoMode != template.language)
+                        continue;
+
+                    template.range = undefined;
+                    suggestions.push(template);
+                }
+            }
+
             // preserve incomplete flag or force it when the definition is not yet analyzed
             const incomplete = (result.incomplete && result.incomplete == true) || owner.deprecatedCandidates.length == 0;
 
@@ -197,6 +324,7 @@ class MonacoCreator {
         }
     }
 
+    // Setup both JS and TS compilation pipelines to work with our scripts. 
     setupMonacoCompilationPipeline(libContent) {
         const typescript = monaco.languages.typescript;
 
@@ -226,6 +354,7 @@ class MonacoCreator {
         }
     }
 
+    // Provide an adornment for BABYLON.ColorX types: color preview
     setupMonacoColorProvider() {
         monaco.languages.registerColorProvider(this.monacoMode, {
             provideColorPresentations: (model, colorInfo) => {
@@ -241,7 +370,9 @@ class MonacoCreator {
                     label = `(${converter(color.red)}, ${converter(color.green)}, ${converter(color.blue)}, ${converter(color.alpha)})`;
                 }
 
-                return [{ label: label }];
+                return [{
+                    label: label
+                }];
             },
 
             provideDocumentColors: (model) => {
@@ -300,9 +431,15 @@ class MonacoCreator {
             }
         };
         editorOptions.minimap.enabled = document.getElementById("minimapToggle1280").classList.contains('checked');
-        this.jsEditor = monaco.editor.create(document.getElementById('jsEditor'), editorOptions);
+        var editorElement = document.getElementById('jsEditor');
+        editorElement.innerHTML = "";
+        editorElement.style.overflow = "unset";
+        this.jsEditor = monaco.editor.create(editorElement, editorOptions);
         this.jsEditor.setValue(oldCode);
 
+        // We cannot call 'analyzeCode' on every keystroke, that's time consuming
+        // So use a debounced version to prevent over processing.
+        // Be careful to keep the proper context for the effective call (this).
         const analyzeCodeDebounced = this.parent.utils.debounceAsync((async) => this.analyzeCode(), 500);
 
         this.jsEditor.onDidChangeModelContent(function () {
@@ -343,10 +480,16 @@ class MonacoCreator {
         const main = this.parent.main;
         const monacoCreator = this;
 
-        this.diffEditor.addCommand(monaco.KeyCode.Escape, function () { main.toggleDiffEditor(monacoCreator, menuPG); });
+        this.diffEditor.addCommand(monaco.KeyCode.Escape, function () {
+            main.toggleDiffEditor(monacoCreator, menuPG);
+        });
         // Adding default VSCode bindinds for previous/next difference
-        this.diffEditor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.F5, function () { main.navigateToNext(); });
-        this.diffEditor.addCommand(monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.F5, function () { main.navigateToPrevious(); });
+        this.diffEditor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.F5, function () {
+            main.navigateToNext();
+        });
+        this.diffEditor.addCommand(monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.F5, function () {
+            main.navigateToPrevious();
+        });
 
         this.diffEditor.focus();
     }
@@ -383,10 +526,18 @@ class MonacoCreator {
     toggleMinimap() {
         var minimapToggle = document.getElementById("minimapToggle1280");
         if (minimapToggle.classList.contains('checked')) {
-            this.jsEditor.updateOptions({ minimap: { enabled: false } });
+            this.jsEditor.updateOptions({
+                minimap: {
+                    enabled: false
+                }
+            });
             this.parent.utils.setToMultipleID("minimapToggle", "innerHTML", 'Minimap <i class="fa fa-square" aria-hidden="true"></i>');
         } else {
-            this.jsEditor.updateOptions({ minimap: { enabled: true } });
+            this.jsEditor.updateOptions({
+                minimap: {
+                    enabled: true
+                }
+            });
             this.parent.utils.setToMultipleID("minimapToggle", "innerHTML", 'Minimap <i class="fa fa-check-square" aria-hidden="true"></i>');
         }
         minimapToggle.classList.toggle('checked');

+ 0 - 524
Playground/js/pbt.js

@@ -1,524 +0,0 @@
-// jsEditor Manipulation
-var PBT = function() {    
-    this.decorationStyles = new Array();
-    this.decorations = new Array();
-    this.lineRanges = new Array();
-    var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
-    var background = "pbt-back-highlight";
-    var margin = "pbt-margin-decor-on";
-    if(localStorage.getItem("bjs-playground-theme") =="dark") {
-        background += "-dark";
-        margin +="-dark";
-    }
-    this.clearDecorLines = function() {
-        this.decorations = jsEditor.deltaDecorations(this.decorations, []);
-    }
-
-    this.setDecorLines = function (lineRanges) {    
-        this.decorationStyles = [];
-
-    var endLineNm = jsEditor.getModel()._lines.length;
-        this.decorationStyles.push({ range: new monaco.Range(1,1,endLineNm,1), options: { isWholeLine: true, inlineClassName: 'pbt-fade' }});
-        
-        for(var i = 0; i < lineRanges.length; i +=2) {          
-            this.decorationStyles.push({ range: new monaco.Range(lineRanges[i],1,lineRanges[i + 1],1), options: { isWholeLine: true, linesDecorationsClassName: margin }});
-            this.decorationStyles.push({ range: new monaco.Range(lineRanges[i],1,lineRanges[i + 1],1), options: { isWholeLine: true, className: background }});
-            this.decorationStyles.push({ range: new monaco.Range(lineRanges[i],1,lineRanges[i + 1],1), options: { isWholeLine: true, inlineClassName: 'pbt-darken' }});
-        }
-
-    this.decorations = jsEditor.deltaDecorations([this.decorations], this.decorationStyles);  
-    }
-
-    this.replaceLines = function(lineRange, text) {   
-        jsEditor.executeEdits("", [
-            { range: new monaco.Range(lineRange[0], 1, lineRange[1], 100000), text: text}
-       ]);
-    }
-
-    this.replaceText = function(line, start, end, text) {   
-        jsEditor.executeEdits("", [
-            { range: new monaco.Range(line, start, line, end), text: text}
-       ]);
-    }
-
-    this.getLineText = function(lineNm) {
-        return jsEditor.getModel().getLineContent(lineNm);
-    }
-
-    this.hideLines = function(lineRanges) {
-        var ranges = [];
-        this.lineRanges = lineRanges;
-        for(var i = 0; i < lineRanges.length; i +=2) {
-            ranges.push(new monaco.Range(lineRanges[i], 1, lineRanges[i + 1], 100000));                
-        }
-        jsEditor.setHiddenAreas(ranges);
-    }
-
-    this.hideRange = function(lineRanges) {       
-        var ranges = [];
-        lineRanges = this.lineRanges.concat(lineRanges);
-        this.lineRanges = lineRanges;
-        for(var i = 0; i < lineRanges.length; i +=2) {
-            ranges.push(new monaco.Range(lineRanges[i], 1, lineRanges[i + 1], 100000));                
-        }
-        jsEditor.setHiddenAreas(ranges);
-    }
-
-    this.showRange = function(lineRanges) {
-        var rangePairs = [];
-        var linePairs = [];       
-        for(var i = 0; i < this.lineRanges.length; i +=2) {
-            rangePairs.push(this.lineRanges[i] + "=" + this.lineRanges[i + 1]);                
-        }        
-        for(var i = 0; i < lineRanges.length; i +=2) {
-            linePairs.push(lineRanges[i] + "=" + lineRanges[i + 1]);                
-        }       
-        var rangeString = rangePairs.join("-");         
-        for(var i = 0; i < linePairs.length; i++) {           
-            rangeString = rangeString.replace(linePairs[i]+"-", "");
-            rangeString = rangeString.replace("-" + linePairs[i], ""); //when last element
-        }        
-        rangeString = rangeString.replace(/-/g, ",");       
-        rangeString = rangeString.replace(/=/g, ",");       
-        lineRanges = rangeString.split(",");      
-        lineRanges = lineRanges.map(function(n){
-            return parseInt(n);
-        });       
-        var ranges = [];
-        for(var i = 0; i < lineRanges.length; i +=2) {
-            ranges.push(new monaco.Range(lineRanges[i], 1, lineRanges[i + 1], 100000));                
-        }
-        this.lineRanges = lineRanges;        
-        jsEditor.setHiddenAreas(ranges);
-    }
-
-    this.editOn = function() {
-        jsEditor.updateOptions({readOnly: false});
-    }
-
-    this.editOff = function() {
-        jsEditor.updateOptions({readOnly: true});
-    }
-
-    //hide menu items
-    this.hideMenu = function() {
-        var headings = document.getElementsByClassName('category');
-        
-        for (var i = 0; i < headings.length; i ++) {
-            headings[i].style.visibility = 'hidden';
-        }
-    
-        headings = document.getElementsByClassName('category right');
-        
-        for (var i = 0; i < headings.length; i ++) {
-            headings[i].style.visibility = 'visible';
-        }
-    }
-
-    //Standard GUI Dialogues
-    this.StandardDialog = function(options) {   
-        options = options||{};
-        var width = options.width||0.5;
-        var height = options.height||0.25;
-        var top = options.top||0;
-        var left = options.left||0;
-        var verticalAlignment = options.verticalAlignment||BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
-        var horizontalAlignment = options.horizontalAlignment||BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-        var text = options.text||"Playground Based Tutorial";   
-        if(options.useImage === undefined) {
-            var useImage = true;
-        }
-        else {
-            var useImage = false;
-        }
-        var imageURL = options.imageURL||"LogoPBT.png";
-        var textBlockWidth = 0.95;
-        var textBlockLeft = "2%";
-        this.container = new BABYLON.GUI.Rectangle();
-        this.container.verticalAlignment = verticalAlignment;
-        this.container.horizontalAlignment = horizontalAlignment;
-        this.container.width = width;
-        this.container.height = height;
-        this.container.cornerRadius = 10;
-        this.container.color = "#364249";
-        this.container.thickness = 4;
-        this.container.background = "#CDC8F9";
-        this.container.top = top;
-        this.container.left = left;   
-        advancedTexture.addControl(this.container); 
-        if(useImage) {
-            this.logoPBT = BABYLON.GUI.Button.CreateImageOnlyButton("but", imageURL);
-            this.logoPBT.width = "100px";
-            this.logoPBT.height = "100px";
-            this.logoPBT.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-            this.logoPBT.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
-            this.logoPBT.top = 2;
-            this.logoPBT.left=2;
-            this.logoPBT.color = "#CDC8F9";
-            this.container.addControl(this.logoPBT);
-            textBlockWidth = 0.6;
-            textBlockLeft = "35%";
-        }
-        this.textBlock = new BABYLON.GUI.TextBlock("text", text);
-        this.textBlock.width = textBlockWidth;
-        this.textBlock.height = 0.7
-        this.textBlock.textWrapping = true;
-        this.textBlock.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-        this.textBlock.color = "#364249";
-        this.textBlock.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
-        this.textBlock.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-        this.textBlock.left = textBlockLeft;
-        this.textBlock.top = 2;
-        this.container.addControl(this.textBlock);
-
-        this.nextButton = BABYLON.GUI.Button.CreateSimpleButton("nextbut", "Next >");
-        this.nextButton.width = 0.2
-        this.nextButton.height = 0.15;
-        this.nextButton.color = "white";
-        this.nextButton.cornerRadius = 5;
-        this.nextButton.background = "#364249";
-        this.nextButton.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
-        this.nextButton.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-        this.nextButton.left = "78%";
-        this.nextButton.top = "80%";
-        this.container.addControl(this.nextButton);
-
-        this.prevButton = BABYLON.GUI.Button.CreateSimpleButton("prevbut", "< Prev");
-        this.prevButton.width = 0.2
-        this.prevButton.height = 0.15;
-        this.prevButton.color = "white";
-        this.prevButton.cornerRadius = 5;
-        this.prevButton.background = "#364249";
-        this.prevButton.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
-        this.prevButton.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-        this.prevButton.left = "2%";
-        this.prevButton.top = "80%";
-        this.container.addControl(this.prevButton); 
-
-        this.showNext = function() {
-            this.nextButton.isVisible = true;
-        }
-
-        this.hideNext = function() {
-            this.nextButton.isVisible = false;
-        }
-
-        this.getNextButton = function() {
-            return this.nextButton;
-        }
-
-        this.getPrevButton = function() {
-            return this.prevButton;
-        }
-
-        this.showPrev = function() {
-            this.prevButton.isVisible = true;
-        }
-
-        this.hidePrev = function() {
-            this.prevButton.isVisible = false;
-        }
-
-        this.setWidth = function(width) {
-            this.container.width = width;
-        }
-
-        this.setHeight = function(height) {
-            this.container.height = height;
-        }
-
-        this.setTop = function(top) {
-            this.container.top = top;
-        }
-
-        this.setLeft = function(left) {
-            this.container.left = left;
-        }
-
-        this.getWidth = function() {
-            return this.container.width;
-        }
-
-        this.getHeight = function() {
-            return this.container.height;
-        }
-
-        this.getTop = function() {
-            return this.container.top;
-        }
-
-        this.getLeft = function() {
-            return this.container.left;
-        }
-
-        this.setHorizontalAlignment = function(hrzAlgn) {
-            this.container.horizontalAlignment = hrzAlgn;
-        }
-
-        this.setVerticalAlignment = function(vrtAlign) {
-            this.container.VerticalAlignmenv = vrtAlign;
-        }
-
-        this.setText = function(text) {
-            this.textBlock.text = text;
-        }
-
-        this.show = function() {
-            this.container.isVisible = true;
-        }
-
-        this.hide = function() {
-            this.container.isVisible = false;
-        }
-
-        return this;
-    }
-
-//Radio and Checkbox Button GUI
-    this.ButtonGroup = function(name, type) {
-        this.name = name;
-        var type = type||"C"; 
-        type = type.substr(0,1).toUpperCase();
-        if(type !="R") {
-            if(type != "S") {
-                if(type != "C") {
-                    type = "C";
-                }
-            }
-        }
-        this.type = type;   
-        this.buttons = new Array();
-        
-        this.addButton = function(text, func, checked) {
-            this.buttons.push({
-                text: text||"", 
-                func: func||function(){}, 
-                checked: checked||false
-            });
-        }
-
-        this.addSlider = function(text, func, unit, onVal, min, max, value) {        
-            this.buttons.push({
-                text: text||"",                
-                func: func||function(){},
-                unit: unit||"", 
-                onVal: onVal||function(){},
-                min: min||0,
-                max: max||10,
-                value: value||0
-            });
-        }
-        return this;
-    }
-
-    this.SelectionDialog = function(options) {
-        options = options||{};
-        var justStarted = true;
-        var width = options.width||0.3;
-        var top = options.top||0;
-        var left = options.left||0;  
-        var verticalAlignment = options.verticalAlignment||BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;
-        var horizontalAlignment = options.horizontalAlignment||BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;    
-        var groups = options.groups; 
-        this.container = new BABYLON.GUI.Rectangle();
-        this.container.verticalAlignment = verticalAlignment;
-        this.container.horizontalAlignment = horizontalAlignment;   
-        var height = 36 * groups.length;
-        for(var i = 0; i < groups.length; i++) {
-            height += 32 * groups[i].buttons.length;
-            if(groups[i].type == "S") {
-                height += 31 * groups[i].buttons.length;
-            }
-        }
-        this.container.height = height + "px";
-        this.container.cornerRadius = 10;
-        this.container.color = "#364249";
-        this.container.thickness = 4;
-        this.container.background = "#CDC8F9";
-        this.container.top = top;
-        this.container.left = left;
-        this.container.width = width;
-        advancedTexture.addControl(this.container);
-        
-        var panel = new BABYLON.GUI.StackPanel(); 
-        panel.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
-        panel.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-        panel.top = 5;
-        panel.left = 5;
-        this.container.addControl(panel);
-
-        var addRadio = function(text, parent, group, func, checked) {
-            checked = checked || false;
-            var button = new BABYLON.GUI.RadioButton();
-            button.width = "20px";
-            button.height = "20px";
-            button.color = "#364249";
-            button.background = "white"; 
-            button.group = group;
-            button.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-            button.justStarted = true;
-            button.func = func;
-
-            button.onIsCheckedChangedObservable.add(function(state) {                       		
-                if (state && !justStarted) {                  
-                    func();
-                }
-            }); 
-
-            var header = BABYLON.GUI.Control.AddHeader(button, text, "200px", { isHorizontal: true, controlFirst: true });
-            header.height = "30px";
-            header.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-            header.left = "4px";
-
-            parent.addControl(header);    
-            button.isChecked = checked; 
-        }
-
-        var addCheckbox = function(text, parent, func, checked) {
-            checked = checked || false;
-            var button = new BABYLON.GUI.Checkbox();
-            button.width = "20px";
-            button.height = "20px";
-            button.color = "#364249";
-            button.background = "white"; 
-            button.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-            
-            button.onIsCheckedChangedObservable.add(function(state) {	
-                func();	
-            }); 
-            
-            var header = BABYLON.GUI.Control.AddHeader(button, text, "200px", { isHorizontal: true, controlFirst: true });
-            header.height = "30px";
-            header.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-            header.left = "4px";
-            
-            parent.addControl(header);    
-            button.isChecked = checked;
-        }
-
-        var addSldr = function(text, parent, func, unit, onValueChange, min, max, value) {         
-            var button = new BABYLON.GUI.Slider();  
-            button.value = value;
-            button.minimum = min;
-            button.maximum = max;
-            button.width = "200px";
-            button.height = "20px";
-            button.color = "#364249";
-            button.background = "white"; 
-            button.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-            button.left = "4px";
-
-            var header = new BABYLON.GUI.TextBlock();
-            header.text = text+": " + value + " " + unit;
-            header.height = "30px";
-            header.color = "#364249";
-            header.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-            header.left = "4px";
-            parent.addControl(header);  
-
-            button.onValueChangedObservable.add(function(value) {
-                header.text = text + onValueChange(value) + " " + unit;
-                func(value);
-            });
-            parent.addControl(button);
-        }
-
-        var groupHeader = function(name) {
-            var groupHeading = new BABYLON.GUI.TextBlock("groupHead", name);
-            groupHeading.width = 0.9;
-            groupHeading.height = "30px";
-            groupHeading.textWrapping = true;
-            groupHeading.color = "black";
-            groupHeading.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-            groupHeading.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-            groupHeading.left = "2px";
-            panel.addControl(groupHeading);
-        }
-
-        var addSpacer = function(name) {
-            var separator = new BABYLON.GUI.Rectangle();
-            separator.width = 1;
-            separator.height = "2px";
-            separator.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
-            separator.background = "#364249";
-            separator.color = "#364249";
-            panel.addControl(separator);
-            
-            groupHeader(name);
-        }
-
-        this.addGroup = function(group) {
-            if(group.type == "R") {
-                for(var i = 0; i < group.buttons.length; i++) {
-                    addRadio(group.buttons[i].text, panel, group.name, group.buttons[i].func, group.buttons[i].checked);
-                }
-            }
-            else if(group.type == "S") {
-                for(var i = 0; i < group.buttons.length; i++) {
-                    addSldr(group.buttons[i].text, panel, group.buttons[i].func, group.buttons[i].unit, group.buttons[i].onVal, group.buttons[i].min, group.buttons[i].max, group.buttons[i].value);
-                }
-            }
-            else {
-                for(var i = 0; i < group.buttons.length; i++) {
-                    addCheckbox(group.buttons[i].text, panel, group.buttons[i].func, group.buttons[i].checked);
-                }
-            }
-            
-            
-        }
-        
-        groupHeader(groups[0].name);
-        this.addGroup(groups[0]);
-        for(var i = 1; i < groups.length; i++) {
-            addSpacer(groups[i].name);
-            this.addGroup(groups[i]);
-        }
-
-        justStarted = false;
-
-        this.setWidth = function(width) {
-            this.container.width = width;
-        }
-
-        this.setTop = function(top) {
-            this.container.top = top;
-        }
-
-        this.setLeft = function(left) {
-            this.container.left = left;
-        }
-
-        this.getWidth = function() {
-            return this.container.width;
-        }
-
-        this.getTop = function() {
-            return this.container.top;
-        }
-
-        this.getLeft = function() {
-            return this.container.left;
-        }
-
-        this.setHorizontalAlignment = function(hrzAlgn) {
-            this.container.horizontalAlignment = hrzAlgn;
-        }
-
-        this.setVerticalAlignment = function(vrtAlign) {
-            this.container.VerticalAlignmenv = vrtAlign;
-        }
-
-        this.show = function() {
-            this.container.isVisible = true;
-        }
-
-        this.hide = function() {
-            this.container.isVisible = false;
-        }
-
-    return this;
-
-    }
-}
-
-    

File diff suppressed because it is too large
+ 0 - 1237
Playground/js/qrcode.js


+ 50 - 32
Playground/js/settingsPG.js

@@ -37,8 +37,7 @@ class SettingsPG {
         if (this.scriptLanguage == "JS") {
             this.defaultScene = "scripts/basic scene.js";
             this.parent.monacoCreator.monacoMode = "javascript";
-        }
-        else if (this.scriptLanguage == "TS") {
+        } else if (this.scriptLanguage == "TS") {
             this.defaultScene = "scripts/basic scene.txt";
             this.parent.monacoCreator.monacoMode = "typescript";
         }
@@ -62,7 +61,9 @@ class SettingsPG {
     setFontSize(size) {
         localStorage.setItem("bjs-playground-font", size);
         this.fontSize = size;
-        this.parent.monacoCreator.jsEditor.updateOptions({ fontSize: size });
+        this.parent.monacoCreator.jsEditor.updateOptions({
+            fontSize: size
+        });
         var array = document.getElementsByClassName("displayFontSize");
         for (var i = 0; i < array.length; i++) {
             var subArray = array[i].children;
@@ -93,9 +94,14 @@ class SettingsPG {
         }
         if (this.scriptLanguage == "JS") {
             this.parent.utils.setToMultipleID("toJSbutton", "removeClass", "floatLeft");
-        }
-        else if (this.scriptLanguage == "TS") {
+            this.parent.utils.setToMultipleID("toJSbutton", "addClass", "selectedLanguage");
+            this.parent.utils.setToMultipleID("toJSbutton", "innerHTML", "Javascript");
+            this.parent.utils.setToMultipleID("toTSbutton", "title", "Switch to TypeScript");
+        } else if (this.scriptLanguage == "TS") {
             this.parent.utils.setToMultipleID("toJSbutton", "addClass", "floatLeft");
+            this.parent.utils.setToMultipleID("toTSbutton", "addClass", "selectedLanguage");
+            this.parent.utils.setToMultipleID("toTSbutton", "innerHTML", "Typescript");
+            this.parent.utils.setToMultipleID("toJSbutton", "title", "Switch to JavaScript");
         }
     };
 
@@ -111,8 +117,7 @@ class SettingsPG {
         if (theme == 'dark') {
             this.vsTheme = 'vs-dark';
             this.parent.utils.setToMultipleID("darkTheme", "addClass", "selected");
-        }
-        else {
+        } else {
             this.vsTheme = 'vs';
             this.parent.utils.setToMultipleID("lightTheme", "addClass", "selected");
         }
@@ -151,6 +156,9 @@ class SettingsPG {
         if (this.mustModifyBJSversion()) {
             this.parent.menuPG.displayWaitDiv();
 
+            window.def = window.define;
+            window.define = undefined;
+
             var apiVersion = localStorage.getItem("bjs-playground-apiversion");
             BABYLON = null;
 
@@ -162,34 +170,44 @@ class SettingsPG {
                 }
             }
 
-            var count = CONFIG_last_versions[position][1].length;
-            for (var i = 0; i < CONFIG_last_versions[position][1].length; i++) {
-                var newBJSscript = document.createElement('script');
-                newBJSscript.src = CONFIG_last_versions[position][1][i];
-                newBJSscript.onload = function () {
-                    count--;
-                    if (count == 0) {
-                        if (BABYLON.Engine.Version.search('-') != -1) this.parent.menuPG.displayVersionNumber("Latest");
-                        else this.parent.menuPG.displayVersionNumber(BABYLON.Engine.Version);
-                        this.parent.utils.setToMultipleID("mainTitle", "innerHTML", "v" + BABYLON.Engine.Version);
-
-                        this.parent.monacoCreator.setCode(localStorage.getItem("bjs-playground-apiversion-tempcode"));
-
-                        localStorage.removeItem("bjs-playground-apiversion");
-                        localStorage.removeItem("bjs-playground-apiversion-tempcode");
-
-                        this.parent.main.compileAndRunFromOutside();
-                    }
-                }.bind(this);
-
-                document.head.appendChild(newBJSscript);
-            }
-        }
-        else return false;
+            var count = CONFIG_last_versions[position][1].length - 1;
+            var newBJSscript = document.createElement('script');
+            newBJSscript.src = CONFIG_last_versions[position][1][0];
+            newBJSscript.onload = function () {
+                for (var i = 1; i < CONFIG_last_versions[position][1].length; i++) {
+                    var newBJSscript = document.createElement('script');
+                    newBJSscript.src = CONFIG_last_versions[position][1][i];
+                    newBJSscript.onload = function () {
+                        count--;
+                        if (count == 0) {
+                            if (BABYLON.Engine.Version.search('-') != -1) this.parent.menuPG.displayVersionNumber("Latest");
+                            else this.parent.menuPG.displayVersionNumber(BABYLON.Engine.Version);
+                            this.parent.utils.setToMultipleID("mainTitle", "innerHTML", "v" + BABYLON.Engine.Version);
+                            this.parent.monacoCreator.addOnMonacoLoadedCallback(() => {
+                                this.parent.monacoCreator.setCode(localStorage.getItem("bjs-playground-apiversion-tempcode"));
+
+
+                                localStorage.removeItem("bjs-playground-apiversion");
+                                localStorage.removeItem("bjs-playground-apiversion-tempcode");
+                                this.parent.main.compileAndRunFromOutside();
+                            });
+
+                            if (window.def) {
+                                window.define = window.def;
+                            }
+
+                        }
+                    }.bind(this);
+
+                    document.head.appendChild(newBJSscript);
+                }
+            }.bind(this);
+            document.head.appendChild(newBJSscript);
+        } else return false;
     };
 
     mustModifyBJSversion() {
         if (localStorage.getItem("bjs-playground-apiversion") && localStorage.getItem("bjs-playground-apiversion") != null && localStorage.getItem("bjs-playground-apiversion") != "Latest") return true;
         else return false;
     };
-};
+};

+ 23 - 26
Playground/js/utils.js

@@ -4,7 +4,7 @@
 class Utils {
     constructor(parent) {
         this.parent = parent;
-        
+
         this.multipleSize = [1280, 1024, 'Mobile'];
     }
 
@@ -14,7 +14,7 @@ class Utils {
     markDirty() {
         if (this.parent.monacoCreator.BlockEditorChange) return;
 
-        this.setToMultipleID("safemodeToggle", "addClass", "checked");!
+        this.setToMultipleID("safemodeToggle", "addClass", "checked");
         this.setToMultipleID('safemodeToggle', 'innerHTML', 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>');
     };
 
@@ -38,7 +38,7 @@ class Utils {
         }
 
         // Not an error with proper location
-        return null;        
+        return null;
     }
 
     /**
@@ -71,8 +71,8 @@ class Utils {
         const jsEditor = this.parent.monacoCreator.jsEditor;
         if (gotoLocation) {
             gotoLocation.addEventListener('click', function () {
-                const position = { 
-                    lineNumber: Number(locationError.lineNumber), 
+                const position = {
+                    lineNumber: Number(locationError.lineNumber),
                     column: Number(locationError.columnNumber)
                 };
 
@@ -89,24 +89,21 @@ class Utils {
         this.multipleSize.forEach(function (size) {
             if (thingToDo == "innerHTML") {
                 document.getElementById(id + size).innerHTML = param
-            }
-            else if (thingToDo == "click") {
+            } else if (thingToDo == "click") {
                 if (param.length > 1) {
                     for (var i = 0; i < param.length; i++) {
                         document.getElementById(id + size).addEventListener("click", param[i]);
                     }
-                }
-                else
+                } else
                     document.getElementById(id + size).addEventListener("click", param);
-            }
-            else if (thingToDo == "addClass") {
+            } else if (thingToDo == "addClass") {
                 document.getElementById(id + size).classList.add(param);
-            }
-            else if (thingToDo == "removeClass") {
+            } else if (thingToDo == "removeClass") {
                 document.getElementById(id + size).classList.remove(param);
-            }
-            else if (thingToDo == "display") {
+            } else if (thingToDo == "display") {
                 document.getElementById(id + size).style.display = param;
+            } else if (thingToDo === "title") {
+                document.getElementById(id + size).setAttribute("title", param);
             }
         });
     };
@@ -115,8 +112,8 @@ class Utils {
      * Function to get the current screen size
      */
     getCurrentSize() {
-        for(var i = 0; i < this.multipleSize.length; i++) {
-            if(document.getElementById("menuButton" + this.multipleSize[i]).offsetHeight > 0) return this.multipleSize[i];
+        for (var i = 0; i < this.multipleSize.length; i++) {
+            if (document.getElementById("menuButton" + this.multipleSize[i]).offsetHeight > 0) return this.multipleSize[i];
         }
     };
 
@@ -134,9 +131,9 @@ class Utils {
             lastCallAt = currentTime
 
             if (isCold && options.leading) {
-                return options.accumulate
-                    ? Promise.resolve(fn.call(this, [args])).then(result => result[0])
-                    : Promise.resolve(fn.call(this, ...args))
+                return options.accumulate ?
+                    Promise.resolve(fn.call(this, [args])).then(result => result[0]) :
+                    Promise.resolve(fn.call(this, ...args))
             }
 
             if (deferred) {
@@ -159,7 +156,7 @@ class Utils {
         function getWait(wait) {
             return (typeof wait === 'function') ? wait() : wait
         }
-    
+
         function defer() {
             const deferred = {}
             deferred.promise = new Promise((resolve, reject) => {
@@ -174,14 +171,14 @@ class Utils {
             clearTimeout(timer)
 
             Promise.resolve(
-                options.accumulate
-                    ? fn.call(this, pendingArgs)
-                    : fn.apply(this, pendingArgs[pendingArgs.length - 1])
-            )
+                    options.accumulate ?
+                    fn.call(this, pendingArgs) :
+                    fn.apply(this, pendingArgs[pendingArgs.length - 1])
+                )
                 .then(thisDeferred.resolve, thisDeferred.reject)
 
             pendingArgs = []
             deferred = null
         }
-    }    
+    }
 }

+ 1 - 1
Playground/js/zipTool.js

@@ -165,7 +165,7 @@ class ZipTool {
 
         this.addContentToZip(zip,
             "index.html",
-            "zipContent/index.html",
+            "/zipContent/index.html",
             this.zipCode,
             false,
             function () {

+ 0 - 3
Playground/package.json

@@ -13,8 +13,5 @@
   },
   "scripts": {
     "test": "browser-sync start --server --files **/* --no-inject-changes --startPath index.html"
-  },
-  "dependencies": {
-    "npm": "^6.13.0"
   }
 }

BIN
Playground/scenes/Xbot.glb


+ 86 - 0
Playground/templates.json

@@ -0,0 +1,86 @@
+[
+  {
+    "label" : "Create a sphere",
+    "documentation" : "https://doc.babylonjs.com/how_to/set_shapes",
+    "insertText" : "var sphere = BABYLON.MeshBuilder.CreateSphere(\"${1:sphere}\", {diameter: ${2:1}}, scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create a box",
+    "documentation" : "https://doc.babylonjs.com/how_to/set_shapes",
+    "insertText" : "var box = BABYLON.MeshBuilder.CreateBox(\"${1:box}\", {size: ${2:1}}, scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create a cylinder",
+    "documentation" : "https://doc.babylonjs.com/how_to/set_shapes",
+    "insertText" : "var cylinder = BABYLON.MeshBuilder.CreateCylinder(\"${1:cylinder}\", {height: ${2:2}, diameter: ${3:1}}, scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create a ground plane",
+    "documentation" : "https://doc.babylonjs.com/how_to/set_shapes",
+    "insertText" : "var ground = BABYLON.MeshBuilder.CreateGround(\"${1:ground}\", {width: ${2:6}, height: ${3:6}}, scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create a point light",
+    "documentation" : "https://doc.babylonjs.com/babylon101/lights#the-point-light",
+    "insertText" : "var pointLight = new BABYLON.PointLight(\"${1:pointLight}\", new BABYLON.Vector3(${2:0},${3:5},${4:0}), scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create a directional light",
+    "documentation" : "https://doc.babylonjs.com/babylon101/lights#the-directional-light",
+    "insertText" : "var dirLight = new BABYLON.DirectionalLight(\"${1:dirLight}\", new BABYLON.Vector3(${2:0.25},${3:-1},${4:-0.25}), scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create a spot light",
+    "documentation" : "https://doc.babylonjs.com/babylon101/lights#the-spot-light",
+    "insertText" : "var spotLight = new BABYLON.SpotLight(\"${1:spotLight}\", new BABYLON.Vector3(${2:0}, ${3:30}, ${4:-10}), new BABYLON.Vector3(${5:0}, ${6:-1}, ${7:0}), ${8:Math.PI / 3}, ${9:2}, scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create a hemispheric light",
+    "documentation" : "https://doc.babylonjs.com/babylon101/lights#the-hemispheric-light",
+    "insertText" : "var hemiLight = new BABYLON.HemisphericLight(\"${1:hemiLight}\", new BABYLON.Vector3(${2:0}, ${3:1}, ${4:0}), scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Load a Node Material from snippet w/callback",
+    "documentation" : "https://doc.babylonjs.com/how_to/node_material#loading-from-a-file-saved-from-the-node-material-editor",
+    "insertText" : "BABYLON.NodeMaterial.ParseFromSnippetAsync(\"${1:your_snippet_url_no_#}\", scene).then(nodeMaterial => {\n     ${2:mesh_to_apply_node_material_to}.material = nodeMaterial;\n});",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Show the Inspector",
+    "documentation" : "https://doc.babylonjs.com/features/playground_debuglayer",
+    "insertText" : "scene.debugLayer.show({\n     embedMode:true\n});",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create an Arc Rotate Camera w/Degrees",
+    "documentation" : "https://doc.babylonjs.com/babylon101/cameras#arc-rotate-camera",
+    "insertText" : "var camera = new BABYLON.ArcRotateCamera(\"${1:camera}\", BABYLON.Tools.ToRadians(${2:90}), BABYLON.Tools.ToRadians(${3:65}), ${4:10}, ${5:BABYLON.Vector3.Zero()}, scene);",
+    "language" : "javascript"
+  },
+  {
+  "label" : "Create an Arc Rotate Camera w/Radians",
+  "documentation" : "https://doc.babylonjs.com/babylon101/cameras#arc-rotate-camera",
+  "insertText" : "var camera = new BABYLON.ArcRotateCamera(\"${1:camera}\", ${2:0}, ${3:Math.PI/2}, ${4:10}, ${5:BABYLON.Vector3.Zero()}, scene);",
+  "language" : "javascript"
+  },
+  {
+  "label" : "Import a Mesh w/callback",
+  "documentation" : "https://doc.babylonjs.com/resources/external_pg_assets",
+  "insertText" : "BABYLON.SceneLoader.ImportMesh(\"${1:meshName}\", \"${2:url to the mesh parent directory}\", \"${3:Mesh filename.fileextension}\", scene, function(newMeshes){\n\n});",
+  "language" : "javascript"
+  },
+  {
+    "label" : "Setup a shadow generator",
+    "documentation" : "https://doc.babylonjs.com/babylon101/shadows",
+    "insertText" : "var shadowGenerator = new BABYLON.ShadowGenerator(${1:size}, ${2:the_light_source});\nshadowGenerator.getShadowMap().renderList.push(${3:the_mesh_that_casts_a_shadow});\n${4:mesh_that_receives_the_shadow}.receiveShadows = true;",
+    "language" : "javascript"
+  }
+]

+ 0 - 55
Playground/test.html

@@ -1,55 +0,0 @@
-<!-- TO DO - What is the purpose of this page ? -->
-
-<div class="navbar-inner" id="topbar">
-    <a class="brand largeOnly" href="#" id="mainTitle">Babylon.js Playground</a>
-    <div class="btn-group">
-        <button class="btn" id="runButton">Run</button>
-        <button class="btn" id="saveButton">Save</button>
-        <button class="btn desktopOnly" id="zipButton">Get .zip</button>
-        <button class="btn desktopOnly" id="newButton">New</button>
-        <button class="btn desktopOnly" id="clearButton">Clear</button>
-    </div>
-    <div class="btn-group desktopOnly">
-        <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-            <span id="currentFontSize">Font: 12</span>
-            <span class="caret"></span>
-        </a>
-        <ul class="dropdown-menu" id="sizeList">
-            <li><a href="#" onclick="setFontSize(12);">12</a></li>
-            <li><a href="#" onclick="setFontSize(14);">14</a></li>
-            <li><a href="#" onclick="setFontSize(16);">16</a></li>
-            <li><a href="#" onclick="setFontSize(18);">18</a></li>
-            <li><a href="#" onclick="setFontSize(20);">20</a></li>
-            <li><a href="#" onclick="setFontSize(22);">22</a></li>
-        </ul>
-    </div>
-    <div class="btn-group desktopOnly">
-        <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-            <span id="currentVersion">Version: Latest</span>
-            <span class="caret"></span>
-        </a>
-        <ul class="dropdown-menu" id="versionList">
-            <li><a href="#" onclick="setVersion('latest');">Latest</a></li>
-            <li><a href="#" onclick="setVersion('2.5');">2.5</a></li>
-        </ul>
-    </div>
-    <div class="btn-group">
-        <label class="btn btn-sm active">
-                    <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
-                </label>
-        <button class="btn btn-sm" id="metadataButton">+Meta data</button>
-        <button class="btn btn-sm" id="editorButton">-Editor</button>
-        <button class="btn btn-sm" id="debugButton">+Debug layer</button>
-    </div>
-    <div class="btn-group pull-right">
-        <button class="btn" id="fullscreenButton">Fullscreen</button>
-        <button class="btn" id="editorFullscreenButton">Editor Fullscreen</button>
-    </div>
-    <div class="btn-group pull-right">
-        <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-            <span id="currentScript">Predefined scripts</span>
-            <span class="caret"></span>
-        </a>
-        <ul class="dropdown-menu" id="scriptsList"></ul>
-    </div>
-</div>

File diff suppressed because it is too large
+ 65 - 0
Playground/textures/PBR_PACK_1_texurePackage.json


BIN
Playground/textures/ParallaxDiffuse.png


BIN
Playground/textures/ParallaxNormal.png


File diff suppressed because it is too large
+ 177 - 0
Playground/textures/TestPack_texurePackage.json


BIN
Playground/textures/opacity.png


+ 3 - 2
Playground/zipContent/index.html

@@ -11,6 +11,7 @@
         <script src="https://preview.babylonjs.com/ammo.js"></script>
         <script src="https://preview.babylonjs.com/cannon.js"></script>
         <script src="https://preview.babylonjs.com/Oimo.js"></script>
+        <script src="https://preview.babylonjs.com/libktx.js"></script>
         <script src="https://preview.babylonjs.com/earcut.min.js"></script>
         <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
@@ -45,8 +46,8 @@
 ####INJECT####
 
         engine.runRenderLoop(function () {
-            if (scene) {
-                scene.render();
+            if (sceneToRender) {
+                sceneToRender.render();
             }
         });
 

+ 2 - 6
Tools/Config/config.json

@@ -142,7 +142,8 @@
             },
             "es6": {
                 "packageName": "@babylonjs/core",
-                "readme": "readme-es6.md"
+                "readme": "readme-es6.md",
+                "license": "license.md"
             }
         }
     },
@@ -263,11 +264,6 @@
                 "output": "babylon.digitalRainPostProcess.min.js",
                 "entry": "./legacy/legacy-digitalRain.ts",
                 "preventLoadLibrary": true
-            },
-            {
-                "output": "babylon.oceanPostProcess.min.js",
-                "entry": "./legacy/legacy-ocean.ts",
-                "preventLoadLibrary": true
             }
         ],
         "build": {

+ 17 - 5
Tools/DevLoader/BabylonLoader.js

@@ -3,6 +3,9 @@
 var BABYLONDEVTOOLS;
 (function(BABYLONDEVTOOLS) {
 
+    var ua = window.navigator.userAgent;
+    var isIE = ua.indexOf("Trident") > 0;
+
     var getJson = function(url, callback, errorCallback) {
         var xhr = new XMLHttpRequest();
         xhr.open('GET', url);
@@ -120,7 +123,10 @@ var BABYLONDEVTOOLS;
         Loader.prototype.dequeue = function() {
             if (queue.length + esmQueue.length === 0) {
                 console.log('Scripts loaded');
-                BABYLON.Engine.ShadersRepository = "/src/Shaders/";
+
+                if (BABYLON) {
+                    BABYLON.Engine.ShadersRepository = "/src/Shaders/";
+                }
                 if (callback) {
                     callback();
                 }
@@ -148,9 +154,15 @@ var BABYLONDEVTOOLS;
             }
 
             var self = this;
-            script.onload = function() {
-                self.dequeue();
-            };
+            if (isIE) { // I love you IE
+                setTimeout(function() {
+                    self.dequeue();
+                }, 500);
+            } else {
+                script.onload = function() {
+                    self.dequeue();
+                };
+            }
             head.appendChild(script);
         }
 
@@ -212,7 +224,7 @@ var BABYLONDEVTOOLS;
         }
 
         Loader.prototype.loadCoreDev = function() {
-            if (typeof document === "undefined") {                
+            if (typeof document === "undefined" || isIE) {                
                 this.loadScript(babylonJSPath + "/dist/preview release/babylon.max.js");
                 return;
             }

+ 1 - 0
Tools/Gulp/helpers/gulp-processShaders.js

@@ -109,6 +109,7 @@ function main(isCore) {
             if (isCore) {
                 if (isInclude) {
                     effectLocation = "../../Materials/effect";
+                    includeText = includeText.replace(/ShadersInclude\//g, "");
                 }
                 else {
                     effectLocation = "../Materials/effect";

+ 6 - 0
Tools/Gulp/helpers/gulp-validateImports.js

@@ -17,6 +17,12 @@ config.modules.forEach(moduleName => {
 
 var validatePath = function(fileLocation, directory, module, lineNumber, errors, isExport) {
     let expressionType = isExport ? "Export" : "Import";
+
+    //Not checking svg files
+    if(module.endsWith(".svg")){
+        return;
+    }
+
     let internalModulePath = path.join(directory, module + ".ts");
 
     // Check .ts path.

+ 1 - 1
Tools/Gulp/tasks/gulpTasks-libraries.js

@@ -84,7 +84,7 @@ var buildExternalLibrariesMultiEntry = function(libraries, settings, isMin) {
     }
 
     // Generate minified file.
-    let wpBuild = webpackStream(wpConfig, webpack);
+    let wpBuild = webpackStream({ config: wpConfig }, webpack);
     return wpBuild.pipe(gulp.dest(outputDirectory));
 }
 

+ 30 - 4
Tools/Gulp/tasks/gulpTasks-localRun.js

@@ -19,14 +19,41 @@ var skipExtensions = [".js", ".glb", ".gltf", ".bin", ".html", ".gif", ".jpg", "
 /**
  * Embedded webserver for test convenience.
  */
-gulp.task("webserver", function() {
+gulp.task("webserver", function () {
     var rootRelativePath = "../../";
     var options = {
         root: rootRelativePath,
         port: 1338,
         livereload: false,
-        middleware: function(connect, opt) {
+        middleware: function (connect, opt) {
             return [function (req, res, next) {
+                const baseUrl =  (req.url.indexOf('dist') !== -1 || req.url.indexOf('Tools') !== -1  || req.url.indexOf('temp/') !== -1);
+                if (!baseUrl && req.headers['referer'] && req.headers['referer'].indexOf('/Playground/') !== -1 && req.url.indexOf('/Playground/') === -1) {
+                    req.url = "/Playground/" + req.url;
+                    res.writeHead(301, {
+                        'Location': req.url
+                    });
+                    return res.end();
+                }
+                const pgMath = req.url.match(/\/Playground\/pg\/(.*)/);
+                if (pgMath) {
+                    const isAFile = req.url.indexOf('.') !== -1;
+                    const withRevision = req.url.match(/\/pg\/(.*)\/revision\/(\d*)/);
+                    if (withRevision) {
+                        revision = withRevision[2];
+                        if (isAFile) {
+                            req.url = req.url.replace(/\/pg\/(.*)\/revision\//gi, "/")
+                        } else {
+                            req.url = req.url.replace(/\/pg\/(.*)\/revision\/(\d*)/gi, "/?pg=$1&revision=$2")
+                        }
+                    } else {
+                        if (isAFile) {
+                            req.url = req.url.replace(/\/pg\//gi, "/")
+                        } else {
+                            req.url = req.url.replace(/\/pg\/(.*)/gi, "/?pg=$1")
+                        }
+                    }
+                }
                 var extension = path.extname(decodeURIComponent(req.originalUrl));
                 if (req.originalUrl.indexOf(config.build.localDevES6FolderName) > -1 && skipExtensions.indexOf(extension) === -1) {
                     // Append .js for es6 modules.
@@ -35,8 +62,7 @@ gulp.task("webserver", function() {
                     }
                 }
                 next();
-              }
-            ]
+            }]
         }
     };
 

+ 78 - 65
Tools/Gulp/tasks/gulpTasks-viewerLibraries.js

@@ -13,93 +13,106 @@ var addModuleExports = require("../helpers/gulp-addModuleExports");
 // Import Build Config
 var config = require("../../Config/config.json");
 
+const webpack = require("webpack");
+
 /**
  * Build the viewer
  */
-var buildViewerLibrary = function(library, settings) {
+var buildViewerLibrary = function (library, settings, out) {
     const sequence = [];
     var outputDirectory = config.build.outputDirectory + settings.build.distOutputDirectory;
 
-    settings.build.outputs.forEach(out => {
-        let wpConfig = require(settings.build.webpack);
-        if (!out.minified) {
-            wpConfig.mode = "development";
-        }
+    let wpConfig = require(settings.build.webpack);
+    if (!out.minified) {
+        wpConfig.mode = "development";
+    }
 
-        let wpBuild = webpackStream(wpConfig, require("webpack"));
+    let wpBuild = webpackStream({ config: wpConfig }, webpack);
 
-        //shoud dtsBundle create the declaration?
-        if (settings.build.dtsBundle) {
-            let event = wpBuild
-                .pipe(through.obj(function(file, enc, cb) {
-                    // only declaration files
-                    const isdts = /\.d\.ts$/.test(file.path);
-                    if (isdts) this.push(file);
-                    cb();
-                }))
-                .pipe(gulp.dest(outputDirectory));
-            // dts-bundle does NOT support (gulp) streams, so files have to be saved and reloaded, 
-            // until I fix it
-            event.on("end", function() {
-                // create the file
-                dtsBundle.bundle(settings.build.dtsBundle);
-                // process the declaration
-                let fileLocation = path.join(path.dirname(settings.build.dtsBundle.main), settings.build.dtsBundle.out);
-                processDeclaration(fileLocation, settings.build.umd.packageName, settings.build.umd.processDeclaration);
-            });
-        }
-
-        let build = wpBuild
-            .pipe(through.obj(function(file, enc, cb) {
-                // only pipe js files
-                const isJs = /\.js$/.test(file.path);
-                if (isJs) this.push(file);
+    //shoud dtsBundle create the declaration?
+    if (settings.build.dtsBundle) {
+        let event = wpBuild
+            .pipe(through.obj(function (file, enc, cb) {
+                // only declaration files
+                const isdts = /\.d\.ts$/.test(file.path);
+                if (isdts) this.push(file);
                 cb();
             }))
-            .pipe(addModuleExports(library.moduleDeclaration, { subModule: false, extendsRoot: false, externalUsingBabylon: true, noBabylonInit: true }));
-
-        function processDestination(dest) {
-            var outputDirectory = config.build.outputDirectory + dest.outputDirectory;
-            build = build
-                .pipe(rename(dest.filename))
-                .pipe(gulp.dest(outputDirectory));
-
-            if (dest.addBabylonDeclaration) {
-                // include the babylon declaration
-                if (dest.addBabylonDeclaration === true) {
-                    dest.addBabylonDeclaration = ["babylon.module.d.ts"];
-                }
-                var decsToAdd = dest.addBabylonDeclaration.map(function(dec) {
-                    return config.build.outputDirectory + '/' + dec;
-                });
-                sequence.unshift(gulp.src(decsToAdd)
-                    .pipe(rename(function(path) {
-                        path.dirname = '';
-                    }))
-                    .pipe(gulp.dest(outputDirectory)))
+            .pipe(gulp.dest(outputDirectory));
+        // dts-bundle does NOT support (gulp) streams, so files have to be saved and reloaded, 
+        // until I fix it
+        event.on("end", function () {
+            // create the file
+            dtsBundle.bundle(settings.build.dtsBundle);
+            // process the declaration
+            let fileLocation = path.join(path.dirname(settings.build.dtsBundle.main), settings.build.dtsBundle.out);
+            processDeclaration(fileLocation, settings.build.umd.packageName, settings.build.umd.processDeclaration);
+        });
+    }
+
+    let build = wpBuild
+        .pipe(through.obj(function (file, enc, cb) {
+            // only pipe js files
+            const isJs = /\.js$/.test(file.path);
+            if (isJs) this.push(file);
+            cb();
+        }))
+        .pipe(addModuleExports(library.moduleDeclaration, {
+            subModule: false,
+            extendsRoot: false,
+            externalUsingBabylon: true,
+            noBabylonInit: true
+        }));
+
+    function processDestination(dest) {
+        var outputDirectory = config.build.outputDirectory + dest.outputDirectory;
+        build = build
+            .pipe(rename(dest.filename))
+            .pipe(gulp.dest(outputDirectory));
+
+        if (dest.addBabylonDeclaration) {
+            // include the babylon declaration
+            if (dest.addBabylonDeclaration === true) {
+                dest.addBabylonDeclaration = ["babylon.module.d.ts"];
             }
+            var decsToAdd = dest.addBabylonDeclaration.map(function (dec) {
+                return config.build.outputDirectory + '/' + dec;
+            });
+            sequence.unshift(gulp.src(decsToAdd)
+                .pipe(rename(function (path) {
+                    path.dirname = '';
+                }))
+                .pipe(gulp.dest(outputDirectory)))
         }
+    }
 
-        out.destinations.forEach(dest => {
-            processDestination(dest);
-        });
+    out.destinations.forEach(dest => {
+        processDestination(dest);
+    });
 
-        sequence.push(build);
+    sequence.push(build);
 
-    });
+    // });
 
     return merge2(sequence);
 }
 
+function buildViewerOutputs(settings, library) {
+    var outputBuilds = settings.build.outputs.map(out => {
+        var buildOutput = function () {
+            return buildViewerLibrary(library, settings, out);
+        }
+        return buildOutput;
+    });
+    return (outputBuilds);
+}
+
 /**
  * Dynamic viewer module creation In Serie for WebPack leaks.
  */
 function buildViewerLibraries(settings) {
-    var tasks = settings.libraries.map(function(library) {
-        var build = function(cb) {
-            return buildViewerLibrary(library, settings);
-        }
-        return build;
+    var tasks = settings.libraries.map(function (library) {
+        return buildViewerOutputs(settings, library);
     });
 
     return gulp.series.apply(this, tasks);
@@ -109,7 +122,7 @@ function buildViewerLibraries(settings) {
 /**
  * Dynamic viewer module creation.
  */
-config.viewerModules.map(function(module) {
+config.viewerModules.map(function (module) {
     var settings = config[module];
 
     // Build the libraries.

+ 1 - 1
Tools/Publisher/tasks/buildBabylonJSAndDependencies.js

@@ -8,7 +8,7 @@ const colorConsole = require("../../NodeHelpers/colorConsole");
  */
 function buildBabylonJSAndDependencies() {
     colorConsole.log("Running gulp compilation");
-    let exec = shelljs.exec("gulp typescript-all", {
+    let exec = shelljs.exec("gulp --max-old-space-size=8192 typescript-all", {
         cwd: path.resolve(__dirname, "../../Gulp/")
     });
     if (exec.code) {

+ 11 - 0
Tools/Publisher/tasks/processEs6Packages.js

@@ -51,6 +51,13 @@ function processEs6Packages(version) {
             fs.copySync(source, destination);
         }
 
+        if (es6Config.license) {
+            let source = path.join(config.computed.rootFolder, es6Config.readme);
+            let destination = path.join(packagePath, "license.md");
+            colorConsole.log("    Copy es6 license file: ", source.cyan, destination.cyan);
+            fs.copySync(source, destination);
+        }
+
         umdPackageJson.name = es6Config.packageName;
         umdPackageJson.version = version;
         umdPackageJson.main = es6Config.index || "index.js";
@@ -68,6 +75,10 @@ function processEs6Packages(version) {
             umdPackageJson.files = files;
         }
 
+        if (es6Config.license && umdPackageJson.files.indexOf("license.md") === -1) {
+            umdPackageJson.files.push("license.md");
+        }
+
         ["dependencies", "peerDependencies", "devDependencies"].forEach(key => {
             if (umdPackageJson[key]) {
                 let dependencies = umdPackageJson[key];

+ 2 - 2
Viewer/src/labs/viewerLabs.ts

@@ -1,10 +1,10 @@
 import { PBREnvironment, EnvironmentDeserializer } from "./environmentSerializer";
 import { Scene } from "babylonjs/scene";
-import { Vector3, Quaternion, Axis, Matrix, TmpVectors } from "babylonjs/Maths/math";
+import { Vector3, Quaternion, Matrix, TmpVectors } from "babylonjs/Maths/math.vector";
 import { SphericalPolynomial } from "babylonjs/Maths/sphericalPolynomial";
 import { ShadowLight } from "babylonjs/Lights/shadowLight";
 import { TextureUtils } from "./texture";
-
+import { Axis } from "babylonjs/Maths/math.axis";
 
 /**
  * The ViewerLabs class will hold functions that are not (!) backwards compatible.

+ 1 - 1
Viewer/src/model/modelAnimation.ts

@@ -1,4 +1,4 @@
-import { Vector3 } from "babylonjs/Maths/math";
+import { Vector3 } from "babylonjs/Maths/math.vector";
 import { AnimationGroup, Animatable } from "babylonjs/Animations/index";
 
 /**

+ 1 - 1
Viewer/src/model/viewerModel.ts

@@ -8,7 +8,7 @@ import { SceneLoaderProgressEvent } from "babylonjs/Loading/sceneLoader";
 import { AnimationGroup } from "babylonjs/Animations/animationGroup";
 import { Animation, Animatable, CircleEase, BackEase, BounceEase, CubicEase, ElasticEase, ExponentialEase, PowerEase, QuadraticEase, QuarticEase, QuinticEase, SineEase } from "babylonjs/Animations/index";
 import { Nullable } from "babylonjs/types";
-import { Quaternion, Vector3 } from "babylonjs/Maths/math";
+import { Quaternion, Vector3 } from "babylonjs/Maths/math.vector";
 import { Tags } from "babylonjs/Misc/tags";
 import { Material } from "babylonjs/Materials/material";
 import { PBRMaterial } from "babylonjs/Materials/PBR/pbrMaterial";

+ 3 - 1
Viewer/tests/karma.conf.js

@@ -1,3 +1,5 @@
+var baseConfig = require('../../tests/karma-browsers.config')
+
 module.exports = function (config) {
     config.set({
         basePath: '../',
@@ -56,6 +58,6 @@ module.exports = function (config) {
             properties: {} // key value pair of properties to add to the <properties> section of the report
         },
 
-        browsers: ['ChromeHeadless']
+        ...baseConfig
     })
 }

+ 3 - 2
Viewer/tests/validation/karma.conf.js

@@ -1,3 +1,5 @@
+var baseConfig = require('../../../tests/karma-browsers.config')
+
 module.exports = function (config) {
     'use strict';
     config.set({
@@ -56,7 +58,6 @@ module.exports = function (config) {
             properties: {} // key value pair of properties to add to the <properties> section of the report
         },
 
-        browsers: ['Chrome']
-
+        ...baseConfig
     });
 };

+ 1 - 0
Viewer/tests/validation/validate.html

@@ -6,6 +6,7 @@
 	<script src="https://preview.babylonjs.com/ammo.js"></script>
 	<script src="https://preview.babylonjs.com/cannon.js"></script>
     <script src="https://preview.babylonjs.com/Oimo.js"></script>
+	<script src="https://preview.babylonjs.com/libktx.js"></script>
     <script src="https://preview.babylonjs.com/babylon.js"></script>
     <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
 

BIN
assets/nme/currentScreenPostProcess.png


+ 125 - 0
azure-pipelines-cd.yml

@@ -0,0 +1,125 @@
+trigger:
+- preview
+
+jobs:
+- job: NetlifyStaticDeploy
+  displayName: 'Deploy'
+  pool:
+    vmImage: 'Ubuntu-16.04'
+    demands: npm
+  steps:
+  - script: 'npm install netlify-cli'
+    displayName: 'npm install netlify'
+  - script: 'npm install --prefix Playground/'
+    displayName: 'npm install playground'
+  - script: 'npm install typescript'
+    displayName: 'npm install typescript'
+# Controllers
+  - script: 'npx netlify link --id=220a52f0-ea85-4244-8342-8ec149cd78d6'
+    displayName: 'netlify link babylonjscontrollers'
+    env:
+      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+  - script: 'npx netlify deploy --prod --dir=assets/meshes/controllers'
+    displayName: 'netlify deploy babylonjscontrollers'
+    env:
+      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+# Sandbox
+  - script: 'npx netlify unlink'
+    displayName: 'netlify unlink'
+  - script: 'npx netlify link --id=4deda23f-f382-458b-897e-2f2111b5f263'
+    displayName: 'netlify link babylonjs-sandbox'
+    env:
+      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+  - script: 'npx netlify deploy --prod --dir=sandbox/'
+    displayName: 'netlify deploy babylonjs-sandbox'
+    env:
+      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+# playground
+#  - script: 'npx netlify unlink'
+#    displayName: 'netlify unlink'
+#  - script: 'npx netlify link --id=9161d5f0-b208-4b86-a281-9300386f6c94'
+#    displayName: 'netlify link babylonjs-playground'
+#    env:
+#      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+#      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+#  - script: 'npx netlify deploy --prod --dir=Playground/'
+#    displayName: 'netlify deploy babylonjs-playground'
+#    env:
+#      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+#      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+# babylonjs-preview
+#  - script: 'npx netlify unlink'
+#    displayName: 'netlify unlink'
+#  - script: 'npx netlify link --id=e1c1c520-e3a4-4d5b-91e6-254f1bea1b6b'
+#    displayName: 'netlify link babylonjs-preview'
+#    env:
+#      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+#      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+#  - script: 'npx netlify deploy --prod --dir="dist/preview release"'
+#    displayName: 'netlify deploy babylonjs-preview'
+#    env:
+#      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+#      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+# assets-babylonjs
+  - script: 'npx netlify unlink'
+    displayName: 'netlify unlink'
+  - script: 'npx netlify link --id=bd58224a-5f56-42de-afd2-ffa72b85fd71'
+    displayName: 'netlify link assets-babylonjs'
+    env:
+      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+  - script: 'npx netlify deploy --prod --dir=assets/'
+    displayName: 'netlify deploy assets-babylonjs'
+    env:
+      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+# nodeeditor
+  - script: 'npm install --prefix Tools/Gulp && npx gulp nodeEditor --gulpfile ./Tools/Gulp/gulpfile.js'
+    displayName: 'gulp build nodeeditor'
+  - script: 'npx netlify unlink'
+    displayName: 'netlify unlink'
+  - script: 'npx netlify link --id=d232f0dc-cdb2-473e-b0f5-91fb1dd1d398'
+    displayName: 'netlify link nodeeditor'
+    env:
+      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+  - script: 'npx netlify deploy --prod --dir=nodeEditor/public'
+    displayName: 'netlify deploy nodeeditor'
+    env:
+      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+# viewer-babylonjs
+  - script: 'npm install --prefix Tools/Gulp && npx gulp viewer --gulpfile ./Tools/Gulp/gulpfile.js'
+    displayName: 'gulp build viewer-babylonjs'
+  - script: 'npx netlify unlink'
+    displayName: 'netlify unlink'
+  - script: 'npx netlify link --id=a32b113f-8187-43ab-9133-8844521f26f4'
+    displayName: 'netlify link viewer-babylonjs'
+    env:
+      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+  - script: 'npx netlify deploy --prod --dir=Viewer/dist/'
+    displayName: 'netlify deploy viewer-babylonjs'
+    env:
+      AZURE_PULLREQUESTID: $(System.PullRequest.PullRequestId)
+      NETLIFY_AUTH_TOKEN: $(babylon.netlify.authToken)
+  - task: AzureFileCopy@2
+    displayName: 'Update Preview Storage'
+    inputs:
+      SourcePath: 'dist/preview release'
+      azureSubscription: 'Visual Studio Enterprise (2bb1afe6-4492-4d3d-9cf8-e658f447d211)'
+      Destination: AzureBlob
+      storage: previewcdn
+      ContainerName: '$web'
+
+  - task: AzureCLI@2
+    displayName: 'Purge preview CDN'
+    inputs:
+      azureSubscription: 'Visual Studio Enterprise(2bb1afe6-4492-4d3d-9cf8-e658f447d211)'
+      scriptType: 'ps'
+      scriptLocation: 'inlineScript'
+      inlineScript: 'az cdn endpoint purge --resource-group Playground-Resources --profile-name Preview-CDN --name babylonjspreview --content-paths /*'

+ 12 - 0
contributing.md

@@ -35,6 +35,18 @@ Please use the Github issues (after discussing them on the forum) **only** for:
 
 We will try to enforce these rules as we consider the forum is a better place for discussions and learnings.
 
+## Online one-click setup for Contributing
+
+You can use Gitpod (A free online VS Code like IDE) for contributing online. With a single click it'll launch a workspace and automatically:
+
+- clone the BabylonJS repo.
+- install the dependencies.
+- run `npm run start` in `Tools/Gulp`.
+
+so that you can start straight away.
+
+[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/BabylonJS/Babylon.js)
+
 ## Pull requests
 
 We are not complicated people, but we still have some [coding guidelines](http://doc.babylonjs.com/how_to/approved_naming_conventions)

File diff suppressed because it is too large
+ 40 - 40
dist/ammo.js


File diff suppressed because it is too large
+ 23 - 0
dist/ammo.wasm.js


BIN
dist/ammo.wasm.wasm


File diff suppressed because it is too large
+ 48733 - 35809
dist/babylon.d.ts


File diff suppressed because it is too large
+ 2 - 2
dist/babylon.js


File diff suppressed because it is too large
+ 70074 - 34735
dist/babylon.max.js


File diff suppressed because it is too large
+ 1 - 1
dist/babylon.max.js.map


File diff suppressed because it is too large
+ 106791 - 80687
dist/babylon.module.d.ts


File diff suppressed because it is too large
+ 1 - 0
dist/basisTranscoder/basis_transcoder.js


BIN
dist/basisTranscoder/basis_transcoder.wasm


File diff suppressed because it is too large
+ 80209 - 0
dist/documentation.d.ts


File diff suppressed because it is too large
+ 126 - 0
dist/glslang/glslang.js


BIN
dist/glslang/glslang.wasm


+ 8 - 0
dist/gltf2Interface/babylon.glTF2Interface.d.ts

@@ -851,6 +851,7 @@ declare module BABYLON.GLTF2 {
 
     /**
      * The glTF validation results
+     * @ignore
      */
     interface IGLTFValidationResults {
         info: {
@@ -882,16 +883,23 @@ declare module BABYLON.GLTF2 {
      * The glTF validation options
      */
     interface IGLTFValidationOptions {
+        /** Uri to use */
         uri?: string;
+        /** Function used to load external resources */
         externalResourceFunction?: (uri: string) => Promise<Uint8Array>;
+        /** Boolean indicating that we need to validate accessor data */
         validateAccessorData?: boolean;
+        /** max number of issues allowed */
         maxIssues?: number;
+        /** Ignored issues */
         ignoredIssues?: Array<string>;
+        /** Value to override severy settings */
         severityOverrides?: Object;
     }
 
     /**
      * The glTF validator object
+     * @ignore
      */
     interface IGLTFValidator {
         validateBytes: (data: Uint8Array, options?: IGLTFValidationOptions) => Promise<IGLTFValidationResults>;

+ 1 - 1
dist/gltf2Interface/package.json

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

File diff suppressed because it is too large
+ 9338 - 7904
dist/gltf_validator.js


File diff suppressed because it is too large
+ 786 - 297
dist/gui/babylon.gui.d.ts


File diff suppressed because it is too large
+ 1978 - 479
dist/gui/babylon.gui.js


File diff suppressed because it is too large
+ 1 - 1
dist/gui/babylon.gui.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/gui/babylon.gui.min.js


File diff suppressed because it is too large
+ 1616 - 616
dist/gui/babylon.gui.module.d.ts


+ 2 - 2
dist/gui/package.json

@@ -4,7 +4,7 @@
     },
     "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.",
-    "version": "4.0.3",
+    "version": "4.1.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.3"
+        "babylonjs": "4.1.0"
     },
     "engines": {
         "node": "*"

+ 2 - 1
dist/gui/readme.md

@@ -26,7 +26,8 @@ If using TypeScript, the typing needs to be added to tsconfig.json:
     ....
     "types": [
         "babylonjs",
-        "babylonjs-gui"
+        "babylonjs-gui",
+        "otherImportsYouMightNeed"
     ],
     ....
 ```

File diff suppressed because it is too large
+ 11 - 12
dist/inspector/babylon.inspector.bundle.js


File diff suppressed because it is too large
+ 18093 - 9285
dist/inspector/babylon.inspector.bundle.max.js


File diff suppressed because it is too large
+ 1 - 1
dist/inspector/babylon.inspector.bundle.max.js.map


+ 270 - 97
dist/inspector/babylon.inspector.d.ts

@@ -18,14 +18,26 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    export class Tools {
+        static StoreLocalBooleanSettings(key: string, value: boolean): void;
+        static ReadLocalBooleanSettings(key: string, defaultValue: boolean): boolean;
+        static LookForItem(item: any, selectedEntity: any): boolean;
+        private static _RecursiveRemoveHiddenMeshesAndHoistChildren;
+        static SortAndFilter(parent: any, items: any[]): any[];
+    }
+}
+declare module INSPECTOR {
     export class GlobalState {
         onSelectionChangedObservable: BABYLON.Observable<any>;
         onPropertyChangedObservable: BABYLON.Observable<PropertyChangedEvent>;
         onInspectorClosedObservable: BABYLON.Observable<BABYLON.Scene>;
         onTabChangedObservable: BABYLON.Observable<number>;
         onPluginActivatedObserver: BABYLON.Nullable<BABYLON.Observer<BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync>>;
-        validationResults: BABYLON.GLTF2.IGLTFValidationResults;
-        onValidationResultsUpdatedObservable: BABYLON.Observable<BABYLON.GLTF2.IGLTFValidationResults>;
+        sceneImportDefaults: {
+            [key: string]: any;
+        };
+        validationResults: BABYLON.Nullable<BABYLON.GLTF2.IGLTFValidationResults>;
+        onValidationResultsUpdatedObservable: BABYLON.Observable<BABYLON.Nullable<BABYLON.GLTF2.IGLTFValidationResults>>;
         onExtensionLoadedObservable: BABYLON.Observable<BABYLON.IGLTFLoaderExtension>;
         glTFLoaderExtensionDefaults: {
             [name: string]: {
@@ -38,6 +50,12 @@ declare module INSPECTOR {
         blockMutationUpdates: boolean;
         selectedLineContainerTitle: string;
         recorder: ReplayRecorder;
+        private _onlyUseEulers;
+        get onlyUseEulers(): boolean;
+        set onlyUseEulers(value: boolean);
+        private _ignoreBackfacesForPicking;
+        get ignoreBackfacesForPicking(): boolean;
+        set ignoreBackfacesForPicking(value: boolean);
         init(propertyChangedObservable: BABYLON.Observable<PropertyChangedEvent>): void;
         prepareGLTFPlugin(loader: BABYLON.GLTFFileLoader): void;
         lightGizmos: Array<BABYLON.LightGizmo>;
@@ -76,21 +94,22 @@ declare module INSPECTOR {
 declare module INSPECTOR {
     interface ITextLineComponentProps {
         label: string;
-        value: string;
+        value?: string;
         color?: string;
         underline?: boolean;
         onLink?: () => void;
+        ignoreValue?: boolean;
     }
     export class TextLineComponent extends React.Component<ITextLineComponentProps> {
         constructor(props: ITextLineComponentProps);
         onLink(): void;
-        renderContent(): JSX.Element;
+        renderContent(): JSX.Element | null;
         render(): JSX.Element;
     }
 }
 declare module INSPECTOR {
     interface ILineContainerComponentProps {
-        globalState: GlobalState;
+        globalState?: GlobalState;
         title: string;
         children: any[] | any;
         closed?: boolean;
@@ -136,7 +155,6 @@ declare module INSPECTOR {
         private _engineInstrumentation;
         private _timerIntervalId;
         constructor(props: IPaneComponentProps);
-        componentWillMount(): void;
         componentWillUnmount(): void;
         render(): JSX.Element | null;
     }
@@ -175,7 +193,7 @@ declare module INSPECTOR {
     }> {
         private _gridMesh;
         constructor(props: IRenderGridPropertyGridComponentProps);
-        componentWillMount(): void;
+        componentDidMount(): void;
         addOrRemoveGrid(): void;
         render(): JSX.Element;
     }
@@ -184,8 +202,6 @@ declare module INSPECTOR {
     export class DebugTabComponent extends PaneComponent {
         private _physicsViewersEnabled;
         constructor(props: IPaneComponentProps);
-        componentWillMount(): void;
-        componentWillUnmount(): void;
         switchPhysicsViewers(): void;
         render(): JSX.Element | null;
     }
@@ -199,6 +215,7 @@ declare module INSPECTOR {
         maximum: number;
         step: number;
         directValue?: number;
+        useEuler?: boolean;
         onChange?: (value: number) => void;
         onInput?: (value: number) => void;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
@@ -214,6 +231,7 @@ declare module INSPECTOR {
         }): boolean;
         onChange(newValueString: any): void;
         onInput(newValueString: any): void;
+        prepareDataToRead(value: number): number;
         render(): JSX.Element;
     }
 }
@@ -229,6 +247,7 @@ declare module INSPECTOR {
         options: ListLineOption[];
         noDirectUpdate?: boolean;
         onSelect?: (value: number) => void;
+        extractValue?: () => number;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class OptionsLineComponent extends React.Component<IOptionsLineComponentProps, {
@@ -261,6 +280,7 @@ declare module INSPECTOR {
         value: number;
         step?: number;
         onChange: (value: number) => void;
+        precision?: number;
     }
     export class NumericInputComponent extends React.Component<INumericInputComponentProps, {
         value: string;
@@ -310,6 +330,7 @@ declare module INSPECTOR {
         propertyName: string;
         step?: number;
         onChange?: (newvalue: BABYLON.Vector3) => void;
+        useEuler?: boolean;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
@@ -321,6 +342,7 @@ declare module INSPECTOR {
         };
         private _localChange;
         constructor(props: IVector3LineComponentProps);
+        getCurrentValue(): any;
         shouldComponentUpdate(nextProps: IVector3LineComponentProps, nextState: {
             isExpanded: boolean;
             value: BABYLON.Vector3;
@@ -338,12 +360,14 @@ declare module INSPECTOR {
     interface IQuaternionLineComponentProps {
         label: string;
         target: any;
+        useEuler?: boolean;
         propertyName: string;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class QuaternionLineComponent extends React.Component<IQuaternionLineComponentProps, {
         isExpanded: boolean;
         value: BABYLON.Quaternion;
+        eulerValue: BABYLON.Vector3;
     }> {
         private _localChange;
         constructor(props: IQuaternionLineComponentProps);
@@ -358,6 +382,34 @@ declare module INSPECTOR {
         updateStateY(value: number): void;
         updateStateZ(value: number): void;
         updateStateW(value: number): void;
+        updateQuaternionFromEuler(): void;
+        updateStateEulerX(value: number): void;
+        updateStateEulerY(value: number): void;
+        updateStateEulerZ(value: number): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    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;
     }
 }
@@ -365,6 +417,7 @@ declare module INSPECTOR {
     interface ICustomPropertyGridComponentProps {
         globalState: GlobalState;
         target: any;
+        lockObject: LockObject;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class CustomPropertyGridComponent extends React.Component<ICustomPropertyGridComponentProps, {
@@ -376,6 +429,16 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    export interface IButtonLineComponentProps {
+        label: string;
+        onClick: () => void;
+    }
+    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
+        constructor(props: IButtonLineComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     interface ICommonMaterialPropertyGridComponentProps {
         globalState: GlobalState;
         material: BABYLON.Material;
@@ -400,22 +463,40 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    interface IFileButtonLineComponentProps {
+        label: string;
+        onClick: (file: File) => void;
+        accept: string;
+    }
+    export class FileButtonLineComponent extends React.Component<IFileButtonLineComponentProps> {
+        private static _IDGenerator;
+        private _id;
+        constructor(props: IFileButtonLineComponentProps);
+        onChange(evt: any): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     export interface ITextureLinkLineComponentProps {
         label: string;
         texture: BABYLON.Nullable<BABYLON.BaseTexture>;
         material?: BABYLON.Material;
         onSelectionChangedObservable?: BABYLON.Observable<any>;
-        onDebugSelectionChangeObservable?: BABYLON.Observable<BABYLON.BaseTexture>;
+        onDebugSelectionChangeObservable?: BABYLON.Observable<TextureLinkLineComponent>;
+        propertyName?: string;
+        onTextureCreated?: (texture: BABYLON.BaseTexture) => void;
+        customDebugAction?: (state: boolean) => void;
     }
     export class TextureLinkLineComponent extends React.Component<ITextureLinkLineComponentProps, {
         isDebugSelected: boolean;
     }> {
         private _onDebugSelectionChangeObserver;
         constructor(props: ITextureLinkLineComponentProps);
-        componentWillMount(): void;
+        componentDidMount(): void;
         componentWillUnmount(): void;
         debugTexture(): void;
         onLink(): void;
+        updateTexture(file: File): void;
         render(): JSX.Element | null;
     }
 }
@@ -430,7 +511,7 @@ declare module INSPECTOR {
     export class StandardMaterialPropertyGridComponent extends React.Component<IStandardMaterialPropertyGridComponentProps> {
         private _onDebugSelectionChangeObservable;
         constructor(props: IStandardMaterialPropertyGridComponentProps);
-        renderTextures(): JSX.Element | null;
+        renderTextures(): JSX.Element;
         render(): JSX.Element;
     }
 }
@@ -439,21 +520,23 @@ declare module INSPECTOR {
         texture: BABYLON.BaseTexture;
         width: number;
         height: number;
-        globalState: GlobalState;
+        globalState?: GlobalState;
+        hideChannelSelect?: boolean;
+    }
+    enum ChannelToDisplay {
+        R = 0,
+        G = 1,
+        B = 2,
+        A = 3,
+        All = 4
     }
     export class TextureLineComponent extends React.Component<ITextureLineComponentProps, {
-        displayRed: boolean;
-        displayGreen: boolean;
-        displayBlue: boolean;
-        displayAlpha: boolean;
+        channel: ChannelToDisplay;
         face: number;
     }> {
         constructor(props: ITextureLineComponentProps);
         shouldComponentUpdate(nextProps: ITextureLineComponentProps, nextState: {
-            displayRed: boolean;
-            displayGreen: boolean;
-            displayBlue: boolean;
-            displayAlpha: boolean;
+            channel: ChannelToDisplay;
             face: number;
         }): boolean;
         componentDidMount(): void;
@@ -472,6 +555,9 @@ declare module INSPECTOR {
         isInteger?: boolean;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
         additionalClass?: string;
+        step?: string;
+        digits?: number;
+        useEuler?: boolean;
     }
     export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
         value: string;
@@ -491,18 +577,6 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
-    interface IFileButtonLineComponentProps {
-        label: string;
-        onClick: (file: File) => void;
-        accept: string;
-    }
-    export class FileButtonLineComponent extends React.Component<IFileButtonLineComponentProps> {
-        constructor(props: IFileButtonLineComponentProps);
-        onChange(evt: any): void;
-        render(): JSX.Element;
-    }
-}
-declare module INSPECTOR {
     interface ITexturePropertyGridComponentProps {
         texture: BABYLON.BaseTexture;
         lockObject: LockObject;
@@ -512,9 +586,9 @@ declare module INSPECTOR {
     export class TexturePropertyGridComponent extends React.Component<ITexturePropertyGridComponentProps> {
         private _adtInstrumentation;
         constructor(props: ITexturePropertyGridComponentProps);
-        componentWillMount(): void;
         componentWillUnmount(): void;
         updateTexture(file: File): void;
+        foreceRefresh(): void;
         render(): JSX.Element;
     }
 }
@@ -558,7 +632,10 @@ declare module INSPECTOR {
     export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMaterialPropertyGridComponentProps> {
         private _onDebugSelectionChangeObservable;
         constructor(props: IPBRMaterialPropertyGridComponentProps);
-        renderTextures(onDebugSelectionChangeObservable: BABYLON.Observable<BABYLON.BaseTexture>): JSX.Element | null;
+        switchAmbientMode(state: boolean): void;
+        switchMetallicMode(state: boolean): void;
+        switchRoughnessMode(state: boolean): void;
+        renderTextures(onDebugSelectionChangeObservable: BABYLON.Observable<TextureLinkLineComponent>): JSX.Element;
         render(): JSX.Element;
     }
 }
@@ -574,7 +651,7 @@ declare module INSPECTOR {
     }> {
         private _onSelectionChangedObserver;
         constructor(props: IRadioButtonLineComponentProps);
-        componentWillMount(): void;
+        componentDidMount(): void;
         componentWillUnmount(): void;
         onChange(): void;
         render(): JSX.Element;
@@ -611,6 +688,7 @@ declare module INSPECTOR {
         updateEnvironmentTexture(file: File): void;
         updateGravity(newValue: BABYLON.Vector3): void;
         updateTimeStep(newValue: number): void;
+        normalizeScene(): void;
         render(): JSX.Element;
     }
 }
@@ -646,7 +724,10 @@ declare module INSPECTOR {
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class CommonShadowLightPropertyGridComponent extends React.Component<ICommonShadowLightPropertyGridComponentProps> {
+        private _internals;
         constructor(props: ICommonShadowLightPropertyGridComponentProps);
+        createShadowGenerator(): void;
+        disposeShadowGenerator(): void;
         render(): JSX.Element;
     }
 }
@@ -710,13 +791,16 @@ declare module INSPECTOR {
     }
     export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGridComponentProps, {
         displayNormals: boolean;
+        displayVertexColors: boolean;
     }> {
         constructor(props: IMeshPropertyGridComponentProps);
         renderWireframeOver(): void;
         renderNormalVectors(): void;
         displayNormals(): void;
+        displayVertexColors(): void;
         onMaterialLink(): void;
         onSourceMeshLink(): void;
+        onSkeletonLink(): void;
         convertPhysicsTypeToString(): string;
         render(): JSX.Element;
     }
@@ -749,30 +833,6 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
-    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 INSPECTOR {
     interface ICommonControlPropertyGridComponentProps {
         globalState: GlobalState;
         control: BABYLON.GUI.Control;
@@ -834,16 +894,6 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
-    export interface IButtonLineComponentProps {
-        label: string;
-        onClick: () => void;
-    }
-    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
-        constructor(props: IButtonLineComponentProps);
-        render(): JSX.Element;
-    }
-}
-declare module INSPECTOR {
     interface IAnimationGroupGridComponentProps {
         globalState: GlobalState;
         animationGroup: BABYLON.AnimationGroup;
@@ -863,7 +913,6 @@ declare module INSPECTOR {
         connect(animationGroup: BABYLON.AnimationGroup): void;
         updateCurrentFrame(animationGroup: BABYLON.AnimationGroup): void;
         shouldComponentUpdate(nextProps: IAnimationGroupGridComponentProps): boolean;
-        componentWillMount(): void;
         componentWillUnmount(): void;
         playOrPause(): void;
         onCurrentFrameChange(value: number): void;
@@ -1004,7 +1053,7 @@ declare module INSPECTOR {
     export class PBRMetallicRoughnessMaterialPropertyGridComponent extends React.Component<IPBRMetallicRoughnessMaterialPropertyGridComponentProps> {
         private _onDebugSelectionChangeObservable;
         constructor(props: IPBRMetallicRoughnessMaterialPropertyGridComponentProps);
-        renderTextures(): JSX.Element | null;
+        renderTextures(): JSX.Element;
         render(): JSX.Element;
     }
 }
@@ -1019,7 +1068,7 @@ declare module INSPECTOR {
     export class PBRSpecularGlossinessMaterialPropertyGridComponent extends React.Component<IPBRSpecularGlossinessMaterialPropertyGridComponentProps> {
         private _onDebugSelectionChangeObservable;
         constructor(props: IPBRSpecularGlossinessMaterialPropertyGridComponentProps);
-        renderTextures(): JSX.Element | null;
+        renderTextures(): JSX.Element;
         render(): JSX.Element;
     }
 }
@@ -1138,7 +1187,7 @@ declare module INSPECTOR {
         private _isPlaying;
         constructor(props: IAnimationGridComponentProps);
         playOrPause(): void;
-        componentWillMount(): void;
+        componentDidMount(): void;
         componentWillUnmount(): void;
         onCurrentFrameChange(value: number): void;
         render(): JSX.Element;
@@ -1157,8 +1206,8 @@ declare module INSPECTOR {
         constructor(props: ISkeletonPropertyGridComponentProps);
         switchSkeletonViewers(): void;
         checkSkeletonViewerState(props: ISkeletonPropertyGridComponentProps): void;
-        componentWillMount(): void;
         shouldComponentUpdate(nextProps: ISkeletonPropertyGridComponentProps): boolean;
+        onOverrideMeshLink(): void;
         render(): JSX.Element;
     }
 }
@@ -1171,6 +1220,7 @@ declare module INSPECTOR {
     }
     export class BonePropertyGridComponent extends React.Component<IBonePropertyGridComponentProps> {
         constructor(props: IBonePropertyGridComponentProps);
+        onTransformNodeLink(): void;
         render(): JSX.Element;
     }
 }
@@ -1211,12 +1261,107 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    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 INSPECTOR {
+    export interface IColor4LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+        onChange?: () => void;
+    }
+    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;
+        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 {
+        globalState: GlobalState;
+        material: BABYLON.NodeMaterial;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: BABYLON.Observable<any>;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class NodeMaterialPropertyGridComponent extends React.Component<INodeMaterialPropertyGridComponentProps> {
+        private _onDebugSelectionChangeObservable;
+        constructor(props: INodeMaterialPropertyGridComponentProps);
+        edit(): void;
+        renderTextures(): JSX.Element | null;
+        renderInputBlock(block: BABYLON.InputBlock): JSX.Element | null;
+        renderInputValues(): JSX.Element | null;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IMultiMaterialPropertyGridComponentProps {
+        globalState: GlobalState;
+        material: BABYLON.MultiMaterial;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: BABYLON.Observable<any>;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class MultiMaterialPropertyGridComponent extends React.Component<IMultiMaterialPropertyGridComponentProps> {
+        constructor(props: IMultiMaterialPropertyGridComponentProps);
+        onMaterialLink(mat: BABYLON.Material): void;
+        renderChildMaterial(): JSX.Element;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     export class PropertyGridTabComponent extends PaneComponent {
         private _timerIntervalId;
         private _lockObject;
         constructor(props: IPaneComponentProps);
         timerRefresh(): void;
-        componentWillMount(): void;
+        componentDidMount(): void;
         componentWillUnmount(): void;
         render(): JSX.Element | null;
     }
@@ -1238,7 +1383,7 @@ declare module INSPECTOR {
         private _backStack;
         private _onSelectionChangeObserver;
         constructor(props: IHeaderComponentProps);
-        componentWillMount(): void;
+        componentDidMount(): void;
         componentWillUnmount(): void;
         goBack(): void;
         renderLogo(): JSX.Element | null;
@@ -1261,21 +1406,43 @@ declare module INSPECTOR {
         globalState: GlobalState;
     }
     export class GLTFComponent extends React.Component<IGLTFComponentProps> {
+        private _onValidationResultsUpdatedObserver;
         constructor(props: IGLTFComponentProps);
         openValidationDetails(): void;
         prepareText(singularForm: string, count: number): string;
-        renderValidation(): JSX.Element;
+        componentDidMount(): void;
+        componentWillUnmount(): void;
+        renderValidation(): JSX.Element | null;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IFileMultipleButtonLineComponentProps {
+        label: string;
+        onClick: (event: any) => void;
+        accept: string;
+    }
+    export class FileMultipleButtonLineComponent extends React.Component<IFileMultipleButtonLineComponentProps> {
+        private static _IDGenerator;
+        private _id;
+        constructor(props: IFileMultipleButtonLineComponentProps);
+        onChange(evt: any): void;
         render(): JSX.Element;
     }
 }
 declare module INSPECTOR {
     export class ToolsTabComponent extends PaneComponent {
         private _videoRecorder;
+        private _screenShotSize;
+        private _useWidthHeight;
+        private _isExporting;
         constructor(props: IPaneComponentProps);
-        componentWillMount(): void;
+        componentDidMount(): void;
         componentWillUnmount(): void;
         captureScreenshot(): void;
+        captureRender(): void;
         recordVideo(): void;
+        importAnimations(event: any): void;
         shouldExport(node: BABYLON.Node): boolean;
         exportGLTF(): void;
         exportBabylon(): void;
@@ -1286,8 +1453,14 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    export class SettingsTabComponent extends PaneComponent {
+        constructor(props: IPaneComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     interface IActionTabsComponentProps {
-        scene: BABYLON.Scene;
+        scene?: BABYLON.Scene;
         noCommands?: boolean;
         noHeader?: boolean;
         noExpand?: boolean;
@@ -1295,7 +1468,8 @@ declare module INSPECTOR {
         popupMode?: boolean;
         onPopup?: () => void;
         onClose?: () => void;
-        globalState: GlobalState;
+        globalState?: GlobalState;
+        initialTab?: BABYLON.DebugLayerTab;
     }
     export class ActionTabsComponent extends React.Component<IActionTabsComponentProps, {
         selectedEntity: any;
@@ -1305,10 +1479,10 @@ declare module INSPECTOR {
         private _onTabChangedObserver;
         private _once;
         constructor(props: IActionTabsComponentProps);
-        componentWillMount(): void;
+        componentDidMount(): void;
         componentWillUnmount(): void;
         changeSelectedTab(index: number): void;
-        renderContent(): JSX.Element;
+        renderContent(): JSX.Element | null;
         onClose(): void;
         onPopup(): void;
         render(): JSX.Element;
@@ -1347,6 +1521,7 @@ declare module INSPECTOR {
         mesh: BABYLON.AbstractMesh;
         extensibilityGroups?: BABYLON.IExplorerExtensibilityGroup[];
         onClick: () => void;
+        globalState: GlobalState;
     }
     export class MeshTreeItemComponent extends React.Component<IMeshTreeItemComponentProps, {
         isBoundingBoxEnabled: boolean;
@@ -1367,10 +1542,10 @@ declare module INSPECTOR {
     export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, {
         isActive: boolean;
     }> {
-        private _onActiveCameraObserver;
+        private _onBeforeRenderObserver;
         constructor(props: ICameraTreeItemComponentProps);
         setActive(): void;
-        componentWillMount(): void;
+        componentDidMount(): void;
         componentWillUnmount(): void;
         render(): JSX.Element;
     }
@@ -1528,13 +1703,6 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
-    export class Tools {
-        static LookForItem(item: any, selectedEntity: any): boolean;
-        private static _RecursiveRemoveHiddenMeshesAndHoistChildren;
-        static SortAndFilter(parent: any, items: any[]): any[];
-    }
-}
-declare module INSPECTOR {
     export interface ITreeItemSelectableComponentProps {
         entity: any;
         selectedEntity?: any;
@@ -1611,12 +1779,15 @@ declare module INSPECTOR {
         private _onPointerObserver;
         private _onSelectionChangeObserver;
         private _selectedEntity;
+        private _posDragEnd;
+        private _scaleDragEnd;
+        private _rotateDragEnd;
         constructor(props: ISceneTreeItemComponentProps);
         shouldComponentUpdate(nextProps: ISceneTreeItemComponentProps, nextState: {
             isSelected: boolean;
             isInPickingMode: boolean;
         }): boolean;
-        componentWillMount(): void;
+        componentDidMount(): void;
         componentWillUnmount(): void;
         onSelect(): void;
         onPickingMode(): void;
@@ -1656,7 +1827,7 @@ declare module INSPECTOR {
         private sceneMutationFunc;
         constructor(props: ISceneExplorerComponentProps);
         processMutation(): void;
-        componentWillMount(): void;
+        componentDidMount(): void;
         componentWillUnmount(): void;
         filterContent(filter: string): void;
         findSiblings(parent: any, items: any[], target: any, goNext: boolean, data: {
@@ -1679,6 +1850,8 @@ declare module INSPECTOR {
         noExpand?: boolean;
         onClose: () => void;
         onPopup: () => void;
+        extensibilityGroups?: BABYLON.IExplorerExtensibilityGroup[];
+        initialTab?: BABYLON.DebugLayerTab;
     }
     export class EmbedHostComponent extends React.Component<IEmbedHostComponentProps> {
         private _once;
@@ -1708,11 +1881,11 @@ declare module INSPECTOR {
         private static _CreateSceneExplorer;
         private static _CreateActionTabs;
         private static _CreateEmbedHost;
-        private static _CreatePopup;
-        static readonly IsVisible: boolean;
+        static _CreatePopup(title: string, windowVariableName: string, width?: number, height?: number): BABYLON.Nullable<HTMLDivElement>;
+        static get IsVisible(): boolean;
         static EarlyAttachToLoader(): void;
         static Show(scene: BABYLON.Scene, userOptions: Partial<BABYLON.IInspectorOptions>): void;
-        private static _CreateCanvasContainer;
+        static _CreateCanvasContainer(parentControl: HTMLElement): void;
         private static _DestroyCanvasContainer;
         private static _Cleanup;
         private static _RemoveElementFromDOM;

File diff suppressed because it is too large
+ 582 - 207
dist/inspector/babylon.inspector.module.d.ts


+ 10 - 7
dist/inspector/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "4.0.3",
+    "version": "4.1.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -29,13 +29,16 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
+        "babylonjs": "4.1.0",
+        "babylonjs-gui": "4.1.0",
+        "babylonjs-loaders": "4.1.0",
+        "babylonjs-materials": "4.1.0",
+        "babylonjs-serializers": "4.1.0",
+        "babylonjs-gltf2interface": "4.1.0"
+    },
+    "devDependencies": {
         "@types/react": "~16.7.3",
-        "@types/react-dom": "~16.0.9",
-        "babylonjs": "4.0.3",
-        "babylonjs-gui": "4.0.3",
-        "babylonjs-loaders": "4.0.3",
-        "babylonjs-serializers": "4.0.3",
-        "babylonjs-gltf2interface": "4.0.3"
+        "@types/react-dom": "~16.0.9"
     },
     "engines": {
         "node": "*"

File diff suppressed because it is too large
+ 22 - 0
dist/libktx.js


BIN
dist/libktx.wasm


File diff suppressed because it is too large
+ 543 - 353
dist/loaders/babylon.glTF1FileLoader.js


File diff suppressed because it is too large
+ 1 - 1
dist/loaders/babylon.glTF1FileLoader.js.map


File diff suppressed because it is too large
+ 2 - 2
dist/loaders/babylon.glTF1FileLoader.min.js


File diff suppressed because it is too large
+ 1297 - 458
dist/loaders/babylon.glTF2FileLoader.js


File diff suppressed because it is too large
+ 1 - 1
dist/loaders/babylon.glTF2FileLoader.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/loaders/babylon.glTF2FileLoader.min.js


File diff suppressed because it is too large
+ 1487 - 617
dist/loaders/babylon.glTFFileLoader.js


File diff suppressed because it is too large
+ 1 - 1
dist/loaders/babylon.glTFFileLoader.js.map


File diff suppressed because it is too large
+ 2 - 2
dist/loaders/babylon.glTFFileLoader.min.js


+ 0 - 0
dist/loaders/babylon.objFileLoader.js


Some files were not shown because too many files changed in this diff