Explorar el Código

Merge pull request #7605 from BabylonJS/master

Nightly
mergify[bot] hace 5 años
padre
commit
bba36dd36f
Se han modificado 31 ficheros con 1164 adiciones y 2319 borrados
  1. 1 0
      Playground/_redirects
  2. 445 400
      Playground/debug.html
  3. 1 7
      Playground/index-local.html
  4. 4 4
      Playground/index.html
  5. 1 2
      Playground/indexStable.html
  6. 352 320
      Playground/indexWebGPU.html
  7. 0 89
      Playground/js/jquery.qrcode.js
  8. 4 4
      Playground/js/monacoCreator.js
  9. 0 1237
      Playground/js/qrcode.js
  10. 4 0
      dist/preview release/babylon.d.ts
  11. 1 1
      dist/preview release/babylon.js
  12. 104 69
      dist/preview release/babylon.max.js
  13. 1 1
      dist/preview release/babylon.max.js.map
  14. 9 0
      dist/preview release/babylon.module.d.ts
  15. 4 0
      dist/preview release/documentation.d.ts
  16. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  17. 12 11
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  18. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  19. 1 1
      dist/preview release/packagesSizeBaseLine.json
  20. 9 0
      dist/preview release/viewer/babylon.module.d.ts
  21. 5 5
      dist/preview release/viewer/babylon.viewer.js
  22. 1 1
      dist/preview release/viewer/babylon.viewer.max.js
  23. 1 0
      dist/preview release/what's new.md
  24. 5 3
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx
  25. 8 1
      src/Gizmos/lightGizmo.ts
  26. 10 8
      src/Materials/Textures/baseTexture.ts
  27. 20 3
      src/Materials/Textures/cubeTexture.ts
  28. 26 31
      src/Shaders/spriteMap.fragment.fx
  29. 127 118
      src/Sprites/spriteMap.ts
  30. BIN
      tests/validation/ReferenceImages/sprite-maps.png
  31. 6 1
      tests/validation/config.json

+ 1 - 0
Playground/_redirects

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

+ 445 - 400
Playground/debug.html

@@ -1,459 +1,504 @@
 <!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">
+
+        <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>
+
+        <!-- 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="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.18.1/min/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">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>
                         </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://forum.babylonjs.com/">Forum</a>
-            </div>
-            <div class='link'>
-                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</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://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="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/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://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/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>
 
 </html>

+ 1 - 7
Playground/index-local.html

@@ -379,13 +379,7 @@
 
     <!-- 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>
+    <script src="https://rawcdn.githack.com/jeromeetienne/jquery-qrcode/master/jquery.qrcode.min.js"></script>
 
     <!-- Main scripts -->
     <script src="/js/config_versions.js"></script>

+ 4 - 4
Playground/index.html

@@ -7,6 +7,7 @@
         <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://use.typekit.net/cta4xsb.css" />
@@ -268,7 +269,7 @@
                                     <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>
+                                    <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>
@@ -430,12 +431,11 @@
         </script>
 
         <!-- Monaco -->
-        <script src="/node_modules/monaco-editor/dev/vs/loader.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.18.1/min/vs/loader.js"></script>
 
         <!-- jQuery -->
         <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
-        <script src="/js/jquery.qrcode.js"></script>
-        <script src="/js/qrcode.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>

+ 1 - 2
Playground/indexStable.html

@@ -407,8 +407,7 @@
 
         <!-- jQuery -->
         <script src="https://code.jquery.com/jquery.min.js"></script>
-        <script src="/js/jquery.qrcode.js"></script>
-        <script src="/js/qrcode.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>

+ 352 - 320
Playground/indexWebGPU.html

@@ -1,392 +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://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>
+        <!-- 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/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" 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 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 removeOnDiff" title="Select Babylon.js version">
-                <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" title="Examples"><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" 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="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="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 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://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 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="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/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/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>
 
 </html>

+ 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 );

+ 4 - 4
Playground/js/monacoCreator.js

@@ -71,15 +71,15 @@ class MonacoCreator {
 
         this.setupDefinitionWorker(libContent);
 
-        require.config({ paths: { 'vs': '/node_modules/monaco-editor/dev/vs' } });
+        require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.18.1/min/vs' } });
 
         require(['vs/editor/editor.main'], () => {
             this.setupMonacoCompilationPipeline(libContent);
             this.setupMonacoColorProvider();
 
-            require(['vs/language/typescript/languageFeatures'], module => {
-                this.hookMonacoCompletionProvider(module.SuggestAdapter);
-            });
+            // require(['vs/language/typescript/languageFeatures'], module => {
+            //     this.hookMonacoCompletionProvider(module.SuggestAdapter);
+            // });
 
             this.parent.main.run();
         });

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 1237
Playground/js/qrcode.js


+ 4 - 0
dist/preview release/babylon.d.ts

@@ -7672,6 +7672,10 @@ declare module BABYLON {
     export class CubeTexture extends BaseTexture {
         private _delayedOnLoad;
         /**
+         * Observable triggered once the texture has been loaded.
+         */
+        onLoadObservable: Observable<CubeTexture>;
+        /**
          * The url of the texture
          */
         url: string;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/babylon.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 104 - 69
dist/preview release/babylon.max.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/babylon.max.js.map


+ 9 - 0
dist/preview release/babylon.module.d.ts

@@ -7759,12 +7759,17 @@ declare module "babylonjs/Materials/Textures/cubeTexture" {
     import { Matrix, Vector3 } from "babylonjs/Maths/math.vector";
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
     import "babylonjs/Engines/Extensions/engine.cubeTexture";
+    import { Observable } from "babylonjs/Misc/observable";
     /**
      * Class for creating a cube texture
      */
     export class CubeTexture extends BaseTexture {
         private _delayedOnLoad;
         /**
+         * Observable triggered once the texture has been loaded.
+         */
+        onLoadObservable: Observable<CubeTexture>;
+        /**
          * The url of the texture
          */
         url: string;
@@ -80899,6 +80904,10 @@ declare module BABYLON {
     export class CubeTexture extends BaseTexture {
         private _delayedOnLoad;
         /**
+         * Observable triggered once the texture has been loaded.
+         */
+        onLoadObservable: Observable<CubeTexture>;
+        /**
          * The url of the texture
          */
         url: string;

+ 4 - 0
dist/preview release/documentation.d.ts

@@ -7672,6 +7672,10 @@ declare module BABYLON {
     export class CubeTexture extends BaseTexture {
         private _delayedOnLoad;
         /**
+         * Observable triggered once the texture has been loaded.
+         */
+        onLoadObservable: Observable<CubeTexture>;
+        /**
          * The url of the texture
          */
         url: string;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


+ 12 - 11
dist/preview release/inspector/babylon.inspector.bundle.max.js

@@ -46514,10 +46514,10 @@ var MeshPropertyGridComponent = /** @class */ (function (_super) {
             { label: "Optimistic", value: babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_2__["AbstractMesh"].OCCLUSION_TYPE_OPTIMISTIC },
             { label: "Strict", value: babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_2__["AbstractMesh"].OCCLUSION_TYPE_STRICT },
         ];
-        var sortedMaterials = scene.materials.slice(0).sort(function (a, b) { return a.name.localeCompare(b.name); });
+        var sortedMaterials = scene.materials.slice(0).sort(function (a, b) { return (a.name || "no name").localeCompare(b.name || "no name"); });
         var materialOptions = sortedMaterials.map(function (m, i) {
             return {
-                label: m.name,
+                label: m.name || "no name",
                 value: i
             };
         });
@@ -46542,15 +46542,16 @@ var MeshPropertyGridComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Is pickable", target: mesh, propertyName: "isPickable", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 mesh.material && (!mesh.material.reservedDataStore || !mesh.material.reservedDataStore.hidden) &&
                     react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__["TextLineComponent"], { label: "Link to material", value: mesh.material.name, onLink: function () { return _this.onMaterialLink(); } }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_12__["OptionsLineComponent"], { label: "Active material", options: materialOptions, target: mesh, propertyName: "material", noDirectUpdate: true, onSelect: function (value) {
-                        if (value < 0) {
-                            mesh.material = null;
-                        }
-                        else {
-                            mesh.material = sortedMaterials[value];
-                        }
-                        _this.forceUpdate();
-                    }, extractValue: function () { return mesh.material ? sortedMaterials.indexOf(mesh.material) : -1; }, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+                !mesh.isAnInstance &&
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_12__["OptionsLineComponent"], { label: "Active material", options: materialOptions, target: mesh, propertyName: "material", noDirectUpdate: true, onSelect: function (value) {
+                            if (value < 0) {
+                                mesh.material = null;
+                            }
+                            else {
+                                mesh.material = sortedMaterials[value];
+                            }
+                            _this.forceUpdate();
+                        }, extractValue: function () { return mesh.material ? sortedMaterials.indexOf(mesh.material) : -1; }, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 mesh.isAnInstance &&
                     react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__["TextLineComponent"], { label: "Source", value: mesh.sourceMesh.name, onLink: function () { return _this.onSourceMeshLink(); } }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_13__["ButtonLineComponent"], { label: "Dispose", onClick: function () {

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


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

@@ -1 +1 @@
-{"thinEngineOnly":112467,"engineOnly":148577,"sceneOnly":503616,"minGridMaterial":634243,"minStandardMaterial":774371}
+{"thinEngineOnly":112467,"engineOnly":148577,"sceneOnly":503616,"minGridMaterial":634243,"minStandardMaterial":774375}

+ 9 - 0
dist/preview release/viewer/babylon.module.d.ts

@@ -7759,12 +7759,17 @@ declare module "babylonjs/Materials/Textures/cubeTexture" {
     import { Matrix, Vector3 } from "babylonjs/Maths/math.vector";
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
     import "babylonjs/Engines/Extensions/engine.cubeTexture";
+    import { Observable } from "babylonjs/Misc/observable";
     /**
      * Class for creating a cube texture
      */
     export class CubeTexture extends BaseTexture {
         private _delayedOnLoad;
         /**
+         * Observable triggered once the texture has been loaded.
+         */
+        onLoadObservable: Observable<CubeTexture>;
+        /**
          * The url of the texture
          */
         url: string;
@@ -80899,6 +80904,10 @@ declare module BABYLON {
     export class CubeTexture extends BaseTexture {
         private _delayedOnLoad;
         /**
+         * Observable triggered once the texture has been loaded.
+         */
+        onLoadObservable: Observable<CubeTexture>;
+        /**
          * The url of the texture
          */
         url: string;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 5 - 5
dist/preview release/viewer/babylon.viewer.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/viewer/babylon.viewer.max.js


+ 1 - 0
dist/preview release/what's new.md

@@ -328,6 +328,7 @@
 - Fix wrong import of _TimeToken ([Sebavan](https://github.com/sebavan/)
 - Fix shadows not rendered correctly when using point lights ([Popov72](https://github.com/Popov72))
 - Prevent depth buffer clear in shadow maps ([Sebavan](https://github.com/sebavan/)
+- Fix for bug where the light gizmo causes lights to flip orientation ([#7603](https://github.com/BabylonJS/Babylon.js/issues/7603)) ([drigax](https://github.com/drigax))
 
 ## Breaking changes
 

+ 5 - 3
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx

@@ -286,11 +286,11 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
             { label: "Strict", value: AbstractMesh.OCCLUSION_TYPE_STRICT },
         ];
 
-        let sortedMaterials = scene.materials.slice(0).sort((a, b) => a.name.localeCompare(b.name));
+        let sortedMaterials = scene.materials.slice(0).sort((a, b) => (a.name || "no name").localeCompare(b.name || "no name"));
 
         var materialOptions = sortedMaterials.map((m, i) => {
             return {
-                label: m.name,
+                label: m.name || "no name",
                 value: i
             }});
 
@@ -325,7 +325,8 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
                         mesh.material && (!mesh.material.reservedDataStore || !mesh.material.reservedDataStore.hidden) &&
                         <TextLineComponent label="Link to material" value={mesh.material.name} onLink={() => this.onMaterialLink()} />
                     }
-                    <OptionsLineComponent label="Active material" options={materialOptions} 
+                    {   !mesh.isAnInstance &&
+                        <OptionsLineComponent label="Active material" options={materialOptions} 
                             target={mesh} propertyName="material" 
                             noDirectUpdate={true}
                             onSelect={(value: number) => {
@@ -339,6 +340,7 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
                             }}
                             extractValue={() => mesh.material ? sortedMaterials.indexOf(mesh.material) : -1}
                             onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
                     {
                         mesh.isAnInstance &&
                         <TextLineComponent label="Source" value={(mesh as any).sourceMesh.name} onLink={() => this.onSourceMeshLink()} />

+ 8 - 1
src/Gizmos/lightGizmo.ts

@@ -85,9 +85,13 @@ export class LightGizmo extends Gizmo {
             // Get update position and direction if the light has it
             if ((light as any).position) {
                 this.attachedMesh!.position.copyFrom((light as any).position);
+                this.attachedMesh!.computeWorldMatrix(true);
+                this._cachedPosition.copyFrom(this.attachedMesh!.position);
             }
             if ((light as any).direction) {
                 this.attachedMesh!.setDirection((light as any).direction);
+                this.attachedMesh!.computeWorldMatrix(true);
+                this._cachedForward.copyFrom(this.attachedMesh!.forward);
             }
 
             this._update();
@@ -127,6 +131,8 @@ export class LightGizmo extends Gizmo {
             } else {
                 // update gizmo to match light
                 this.attachedMesh!.position.copyFrom((this._light as any).position);
+                this.attachedMesh!.computeWorldMatrix(true);
+                this._cachedPosition.copyFrom(this.attachedMesh!.position);
             }
 
         }
@@ -139,7 +145,8 @@ export class LightGizmo extends Gizmo {
             } else if (Vector3.DistanceSquared(this.attachedMesh!.forward, (this._light as any).direction) > 0.0001) {
                 // update gizmo to match light
                 this.attachedMesh!.setDirection((this._light as any).direction);
-                this._cachedForward.copyFrom(this._lightMesh.forward);
+                this.attachedMesh!.computeWorldMatrix(true);
+                this._cachedForward.copyFrom(this.attachedMesh!.forward);
             }
         }
         if (!this._light.isEnabled()) {

+ 10 - 8
src/Materials/Textures/baseTexture.ts

@@ -773,14 +773,16 @@ export class BaseTexture implements IAnimatable {
             else {
                 var onLoadObservable = (texture as any).onLoadObservable as Observable<BaseTexture>;
 
-                let onLoadCallback = () => {
-                    onLoadObservable.removeCallback(onLoadCallback);
-                    if (--numRemaining === 0) {
-                        callback();
-                    }
-                };
-
-                onLoadObservable.add(onLoadCallback);
+                if (onLoadObservable) {
+                    let onLoadCallback = () => {
+                        onLoadObservable.removeCallback(onLoadCallback);
+                        if (--numRemaining === 0) {
+                            callback();
+                        }
+                    };
+
+                    onLoadObservable.add(onLoadCallback);
+                }
             }
         }
     }

+ 20 - 3
src/Materials/Textures/cubeTexture.ts

@@ -10,6 +10,7 @@ import { _TypeStore } from '../../Misc/typeStore';
 
 import "../../Engines/Extensions/engine.cubeTexture";
 import { StringTools } from '../../Misc/stringTools';
+import { Observable } from '../../Misc/observable';
 
 /**
  * Class for creating a cube texture
@@ -18,6 +19,11 @@ export class CubeTexture extends BaseTexture {
     private _delayedOnLoad: Nullable<() => void>;
 
     /**
+     * Observable triggered once the texture has been loaded.
+     */
+    public onLoadObservable: Observable<CubeTexture> = new Observable<CubeTexture>();
+
+    /**
      * The url of the texture
      */
     public url: string;
@@ -212,6 +218,13 @@ export class CubeTexture extends BaseTexture {
 
         this._files = files;
 
+        let onLoadProcessing = () => {
+            this.onLoadObservable.notifyObservers(this);
+            if (onLoad) {
+                onLoad();
+            }
+        };
+
         if (!this._texture) {
             if (!scene.useDelayedTextureLoading) {
                 if (prefiltered) {
@@ -220,14 +233,16 @@ export class CubeTexture extends BaseTexture {
                 else {
                     this._texture = scene.getEngine().createCubeTexture(rootUrl, scene, files, noMipmap, onLoad, onError, this._format, forcedExtension, false, lodScale, lodOffset);
                 }
+                this._texture?.onLoadedObservable.add(() => this.onLoadObservable.notifyObservers(this));
+
             } else {
                 this.delayLoadState = Constants.DELAYLOADSTATE_NOTLOADED;
             }
-        } else if (onLoad) {
+        } else {
             if (this._texture.isReady) {
-                Tools.SetImmediate(() => onLoad());
+                Tools.SetImmediate(() => onLoadProcessing());
             } else {
-                this._texture.onLoadedObservable.add(onLoad);
+                this._texture.onLoadedObservable.add(() => onLoadProcessing());
             }
         }
     }
@@ -303,6 +318,8 @@ export class CubeTexture extends BaseTexture {
             else {
                 this._texture = scene.getEngine().createCubeTexture(this.url, scene, this._files, this._noMipmap, this._delayedOnLoad, null, this._format, forcedExtension);
             }
+
+            this._texture?.onLoadedObservable.add(() => this.onLoadObservable.notifyObservers(this));
         }
     }
 

+ 26 - 31
src/Shaders/spriteMap.fragment.fx

@@ -12,8 +12,6 @@ uniform vec2 spriteMapSize;
 uniform vec2 outputSize;
 uniform vec2 stageSize;
 
-uniform float maxAnimationFrames;
-
 uniform sampler2D frameMap;
 uniform sampler2D tileMaps[LAYERS];
 uniform sampler2D animationMap;
@@ -22,75 +20,72 @@ uniform vec3 colorMul;
 
 float mt;
 
-float fdStep = 1. / 4.;
+const float fdStep = 1. / 4.;
+const float aFrameSteps = 1. / MAX_ANIMATION_FRAMES;
 
 mat4 getFrameData(float frameID){
     float fX = frameID / spriteCount;
     return mat4(
-        texture(frameMap, vec2(fX, 0.), 0.),
-        texture(frameMap, vec2(fX, fdStep * 1.), 0.),
-        texture(frameMap, vec2(fX, fdStep * 2.), 0.),
+        texture2D(frameMap, vec2(fX, 0.), 0.),
+        texture2D(frameMap, vec2(fX, fdStep * 1.), 0.),
+        texture2D(frameMap, vec2(fX, fdStep * 2.), 0.),
         vec4(0.)
     );
 }
 
 void main(){
-    vec4 color = vec4(0.);    
+    vec4 color = vec4(0.);
     vec2 tileUV = fract(tUV);
     #ifdef FLIPU
         tileUV.y = 1.0 - tileUV.y;
     #endif
 
-    vec2 tileID = floor(tUV);	
+    vec2 tileID = floor(tUV);
     vec2 sheetUnits = 1. / spriteMapSize;
     float spriteUnits = 1. / spriteCount;
-    vec2 stageUnits = 1. / stageSize;        
+    vec2 stageUnits = 1. / stageSize;
     
-    for(int i = 0; i < LAYERS; i++){
+    for(int i = 0; i < LAYERS; i++) {
         float frameID;
-            switch(i){
-                #define LAYER_ID_SWITCH      
-            }        
-        
-        vec4 animationData = texture(animationMap, vec2((frameID + 0.5) / spriteCount, 0.), 0.); 
-        
-        if(animationData.y > 0.){
+        #define LAYER_ID_SWITCH
+
+        vec4 animationData = texture2D(animationMap, vec2((frameID + 0.5) / spriteCount, 0.), 0.); 
         
+        if(animationData.y > 0.) {
+
             mt = mod(time*animationData.z, 1.0);
-            float aFrameSteps = 1. / maxAnimationFrames;
-            
-            for(float f = 0.; f < maxAnimationFrames; f++){
+            for(float f = 0.; f < MAX_ANIMATION_FRAMES; f++){
                 if(animationData.y > mt){
                     frameID = animationData.x;
                     break;
                 }
                 
-                animationData = texture(animationMap, vec2((frameID + 0.5) / spriteCount, aFrameSteps * f), 0.); 
+                animationData = texture2D(animationMap, vec2((frameID + 0.5) / spriteCount, aFrameSteps * f), 0.); 
             }
         }
 
         //Get Animation Frame
-        mat4 frameData = getFrameData(frameID + 0.5);	
-        vec2 frameSize = (frameData[0].wz) / spriteMapSize;    
-        vec2 offset = frameData[0].xy * sheetUnits;	
+        mat4 frameData = getFrameData(frameID + 0.5);
+        vec2 frameSize = (frameData[0].wz) / spriteMapSize;
+        vec2 offset = frameData[0].xy * sheetUnits;
         vec2 ratio = frameData[2].xy / frameData[0].wz;
 
         //rotated
-        if(frameData[2].z == 1.){
+        if (frameData[2].z == 1.){
             tileUV.xy = tileUV.yx;
         }
 
-        if(i == 0){
-            color = texture(spriteSheet, tileUV * frameSize+offset);
+        if (i == 0){
+            color = texture2D(spriteSheet, tileUV * frameSize+offset);
         } else {
-            vec4 nc = texture(spriteSheet, tileUV * frameSize+offset);
+            vec4 nc = texture2D(spriteSheet, tileUV * frameSize+offset);
             float alpha = min(color.a + nc.a, 1.0);
             vec3 mixed = mix(color.xyz, nc.xyz, nc.a);
             color = vec4(mixed, alpha);
-        }	
+        }
     }
 
-    color.xyz*=colorMul;   
+    color.xyz *= colorMul;
     
-    gl_FragColor =  color;
+    gl_FragColor = color;
 }

+ 127 - 118
src/Sprites/spriteMap.ts

@@ -149,7 +149,7 @@ export class SpriteMap implements ISpriteMap {
         let am = this._createTileAnimationBuffer(buffer);
         this._animationMap.dispose();
         this._animationMap = am;
-        this._material.setTexture('animationMap', this._animationMap);
+        this._material.setTexture("animationMap", this._animationMap);
     }
 
     /** Scene that the SpriteMap was created in */
@@ -183,124 +183,133 @@ export class SpriteMap implements ISpriteMap {
      */
     constructor(name : string, atlasJSON: ISpriteJSONAtlas, spriteSheet: Texture, options: ISpriteMapOptions, scene : Scene) {
 
-    this.name = name;
-    this.sprites = [];
-    this.atlasJSON = atlasJSON;
-    this.sprites = this.atlasJSON['frames'];
-    this.spriteSheet = spriteSheet;
-
-    /**
-    * Run through the options and set what ever defaults are needed that where not declared.
-    */
-    this.options = options;
-    this.options.stageSize = this.options.stageSize || new Vector2(1, 1);
-    this.options.outputSize = this.options.outputSize || this.options.stageSize;
-    this.options.outputPosition = this.options.outputPosition || Vector3.Zero();
-    this.options.outputRotation = this.options.outputRotation || Vector3.Zero();
-    this.options.layerCount = this.options.layerCount || 1;
-    this.options.maxAnimationFrames = this.options.maxAnimationFrames || 0;
-    this.options.baseTile = this.options.baseTile || 0;
-    this.options.flipU = this.options.flipU || false;
-    this.options.colorMultiply = this.options.colorMultiply || new Vector3(1, 1, 1);
-
-    this._scene = scene;
-
-    this._frameMap = this._createFrameBuffer();
-
-    this._tileMaps = new Array();
-    for (let i = 0; i < this.options.layerCount; i++) {
-        this._tileMaps.push(this._createTileBuffer(null, i));
-    }
+        this.name = name;
+        this.sprites = [];
+        this.atlasJSON = atlasJSON;
+        this.sprites = this.atlasJSON["frames"];
+        this.spriteSheet = spriteSheet;
+
+        /**
+        * Run through the options and set what ever defaults are needed that where not declared.
+        */
+        this.options = options;
+        options.stageSize = options.stageSize || new Vector2(1, 1);
+        options.outputSize = options.outputSize || options.stageSize;
+        options.outputPosition = options.outputPosition || Vector3.Zero();
+        options.outputRotation = options.outputRotation || Vector3.Zero();
+        options.layerCount = options.layerCount || 1;
+        options.maxAnimationFrames = options.maxAnimationFrames || 0;
+        options.baseTile = options.baseTile || 0;
+        options.flipU = options.flipU || false;
+        options.colorMultiply = options.colorMultiply || new Vector3(1, 1, 1);
+
+        this._scene = scene;
+
+        this._frameMap = this._createFrameBuffer();
+
+        this._tileMaps = new Array();
+        for (let i = 0; i < options.layerCount; i++) {
+            this._tileMaps.push(this._createTileBuffer(null, i));
+        }
 
-    this._animationMap = this._createTileAnimationBuffer(null);
+        this._animationMap = this._createTileAnimationBuffer(null);
 
-    let defines = [];
-    defines.push("#define LAYERS " + this.options.layerCount);
+        let defines = [];
+        defines.push("#define LAYERS " + options.layerCount);
 
-    if (this.options.flipU) {
-        defines.push("#define FLIPU");
-    }
+        if (options.flipU) {
+            defines.push("#define FLIPU");
+        }
 
-    let shaderString: string = Effect.ShadersStore['spriteMapPixelShader'];
-    let layerSampleString: string = '';
+        defines.push(`#define MAX_ANIMATION_FRAMES ${options.maxAnimationFrames}.0`);
 
-    for (let i = 0; i < this.options.layerCount; i++) {
-        layerSampleString += 'case ' + i + ' : frameID = texture(tileMaps[' + i + '], (tileID + 0.5) / stageSize, 0.).x;';
-        layerSampleString += 'break;';
-    }
+        let shaderString: string = Effect.ShadersStore["spriteMapPixelShader"];
 
-    Effect.ShadersStore['spriteMap' + this.name + 'PixelShader'] = shaderString.replace('#define LAYER_ID_SWITCH',  layerSampleString);
-
-    this._material = new ShaderMaterial("spriteMap:" + this.name, this._scene, {
-        vertex: "spriteMap",
-        fragment: "spriteMap" + this.name,
-    }, {
-        defines,
-        attributes: ["position", "normal", "uv"],
-        uniforms: [
-            "worldViewProjection",
-            "time",
-            'stageSize',
-            'outputSize',
-            'spriteMapSize',
-            'spriteCount',
-            'time',
-            'maxAnimationFrames',
-            'colorMul',
-            'mousePosition',
-            'curTile',
-            'flipU'
-        ],
-        samplers: [
-           "spriteSheet", "frameMap", "tileMaps", "animationMap"
-        ],
-        needAlphaBlending: true
-    });
-
-    this._time = 0;
-
-    this._material.setFloat('spriteCount', this.spriteCount);
-    this._material.setFloat('maxAnimationFrames', this.options.maxAnimationFrames);
-    this._material.setVector2('stageSize', this.options.stageSize);
-    this._material.setVector2('outputSize', this.options.outputSize);
-    this._material.setTexture('spriteSheet', this.spriteSheet);
-    this._material.setVector2('spriteMapSize', new Vector2(1, 1));
-    this._material.setVector3('colorMul', this.options.colorMultiply);
-
-    let tickSave = 0;
-
-    const bindSpriteTexture = () => {
-        if ((this.spriteSheet) && this.spriteSheet.isReady()) {
-            if (this.spriteSheet._texture) {
-                this._material.setVector2('spriteMapSize', new Vector2(this.spriteSheet._texture.baseWidth || 1, this.spriteSheet._texture.baseHeight || 1));
-                return;
+        let layerSampleString: string;
+        if (this._scene.getEngine().webGLVersion === 1) {
+            layerSampleString = "";
+            for (let i = 0; i < options.layerCount; i++) {
+                layerSampleString += `if (${i} == i) { frameID = texture2D(tileMaps[${i}], (tileID + 0.5) / stageSize, 0.).x; }`;
             }
         }
-        if (tickSave < 100) {
-            setTimeout(() => {tickSave++; bindSpriteTexture(); }, 100);
+        else {
+            layerSampleString = "switch(i) {";
+            for (let i = 0; i < options.layerCount; i++) {
+                layerSampleString += "case " + i + " : frameID = texture(tileMaps[" + i + "], (tileID + 0.5) / stageSize, 0.).x;";
+                layerSampleString += "break;";
+            }
+            layerSampleString += "}";
         }
-    };
 
-    bindSpriteTexture();
+        Effect.ShadersStore["spriteMap" + this.name + "PixelShader"] = shaderString.replace("#define LAYER_ID_SWITCH",  layerSampleString);
+
+        this._material = new ShaderMaterial("spriteMap:" + this.name, this._scene, {
+            vertex: "spriteMap",
+            fragment: "spriteMap" + this.name,
+        }, {
+            defines,
+            attributes: ["position", "normal", "uv"],
+            uniforms: [
+                "worldViewProjection",
+                "time",
+                "stageSize",
+                "outputSize",
+                "spriteMapSize",
+                "spriteCount",
+                "time",
+                "colorMul",
+                "mousePosition",
+                "curTile",
+                "flipU"
+            ],
+            samplers: [
+            "spriteSheet", "frameMap", "tileMaps", "animationMap"
+            ],
+            needAlphaBlending: true
+        });
 
-    this._material.setVector3('colorMul', this.options.colorMultiply);
-    this._material.setTexture("frameMap", this._frameMap);
-    this._material.setTextureArray("tileMaps", this._tileMaps);
-    this._material.setTexture("animationMap", this._animationMap);
-    this._material.setFloat('time', this._time);
+        this._time = 0;
 
-    this._output = Mesh.CreatePlane(name + ":output", 1, scene, true);
-    this._output.scaling.x = this.options.outputSize.x;
-    this._output.scaling.y = this.options.outputSize.y;
+        this._material.setFloat("spriteCount", this.spriteCount);
+        this._material.setVector2("stageSize", options.stageSize);
+        this._material.setVector2("outputSize", options.outputSize);
+        this._material.setTexture("spriteSheet", this.spriteSheet);
+        this._material.setVector2("spriteMapSize", new Vector2(1, 1));
+        this._material.setVector3("colorMul", options.colorMultiply);
 
-    let obfunction = () => {
-        this._time += this._scene.getEngine().getDeltaTime();
-        this._material.setFloat('time', this._time);
-    };
+        let tickSave = 0;
 
-    this._scene.onBeforeRenderObservable.add(obfunction);
-    this._output.material = this._material;
+        const bindSpriteTexture = () => {
+            if ((this.spriteSheet) && this.spriteSheet.isReady()) {
+                if (this.spriteSheet._texture) {
+                    this._material.setVector2("spriteMapSize", new Vector2(this.spriteSheet._texture.baseWidth || 1, this.spriteSheet._texture.baseHeight || 1));
+                    return;
+                }
+            }
+            if (tickSave < 100) {
+                setTimeout(() => {tickSave++; bindSpriteTexture(); }, 100);
+            }
+        };
+
+        bindSpriteTexture();
+
+        this._material.setVector3("colorMul", options.colorMultiply);
+        this._material.setTexture("frameMap", this._frameMap);
+        this._material.setTextureArray("tileMaps", this._tileMaps);
+        this._material.setTexture("animationMap", this._animationMap);
+        this._material.setFloat("time", this._time);
+
+        this._output = Mesh.CreatePlane(name + ":output", 1, scene, true);
+        this._output.scaling.x = options.outputSize.x;
+        this._output.scaling.y = options.outputSize.y;
+
+        let obfunction = () => {
+            this._time += this._scene.getEngine().getDeltaTime();
+            this._material.setFloat("time", this._time);
+        };
 
+        this._scene.onBeforeRenderObservable.add(obfunction);
+        this._output.material = this._material;
     }
 
     /**
@@ -359,15 +368,15 @@ export class SpriteMap implements ISpriteMap {
             data.push(0, 0, 0, 0); //frame
             data.push(0, 0, 0, 0); //spriteSourceSize
             data.push(0, 0, 0, 0); //sourceSize, rotated, trimmed
-            data.push(0, 0, 0, 0); //Keep it pow2 cause I'm cool like that... it helps with sampling accuracy as well. Plus then we have 4 other parameters for future stuff.
+            data.push(0, 0, 0, 0); //Keep it pow2 cause I"m cool like that... it helps with sampling accuracy as well. Plus then we have 4 other parameters for future stuff.
         }
         //Second Pass
         for (let i = 0; i < this.spriteCount; i++) {
-            let f = this.sprites[i]['frame'];
-            let sss = this.sprites[i]['spriteSourceSize'];
-            let ss = this.sprites[i]['sourceSize'];
-            let r = (this.sprites[i]['rotated']) ? 1 : 0;
-            let t = (this.sprites[i]['trimmed']) ? 1 : 0;
+            let f = this.sprites[i]["frame"];
+            let sss = this.sprites[i]["spriteSourceSize"];
+            let ss = this.sprites[i]["sourceSize"];
+            let r = (this.sprites[i]["rotated"]) ? 1 : 0;
+            let t = (this.sprites[i]["trimmed"]) ? 1 : 0;
 
             //frame
             data[i * 4] = f.x;
@@ -543,16 +552,16 @@ export class SpriteMap implements ISpriteMap {
     * Exports the .tilemaps file
     */
     public saveTileMaps(): void {
-        let maps = '';
+        let maps = "";
         for (var i = 0; i < this._tileMaps.length; i++) {
-            if (i > 0) {maps += '\n\r'; }
+            if (i > 0) {maps += "\n\r"; }
 
             maps += this._tileMaps[i]!._texture!._bufferView!.toString();
         }
-        var hiddenElement = document.createElement('a');
-        hiddenElement.href = 'data:octet/stream;charset=utf-8,' + encodeURI(maps);
-        hiddenElement.target = '_blank';
-        hiddenElement.download = this.name + '.tilemaps';
+        var hiddenElement = document.createElement("a");
+        hiddenElement.href = "data:octet/stream;charset=utf-8," + encodeURI(maps);
+        hiddenElement.target = "_blank";
+        hiddenElement.download = this.name + ".tilemaps";
         hiddenElement.click();
         hiddenElement.remove();
     }
@@ -569,9 +578,9 @@ export class SpriteMap implements ISpriteMap {
 
         xhr.onload = () =>
         {
-            let data = xhr.response.split('\n\r');
+            let data = xhr.response.split("\n\r");
             for (let i = 0; i < _lc; i++) {
-                let d = (data[i].split(',')).map(Number);
+                let d = (data[i].split(",")).map(Number);
                 let t = this._createTileBuffer(d);
                 this._tileMaps[i].dispose();
                 this._tileMaps[i] = t;

BIN
tests/validation/ReferenceImages/sprite-maps.png


+ 6 - 1
tests/validation/config.json

@@ -5,7 +5,12 @@
             "title": "Black and White post-process",
             "playgroundId": "#N55Q2M#0",
             "referenceImage": "bwpp.png"
-        },             
+        },           
+        {
+            "title": "Sprite maps",
+            "playgroundId": "#ARLADE#22",
+            "referenceImage": "sprite-maps.png"
+        },              
         {
             "title": "Point light shadows",
             "playgroundId": "#U2F7P9#4",