diff --git a/package-lock.json b/package-lock.json
index 39697df16e..53405e9b71 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "scratch-editor",
-  "version": "11.0.0",
+  "version": "11.1.0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "scratch-editor",
-      "version": "11.0.0",
+      "version": "11.1.0",
       "license": "AGPL-3.0-only",
       "workspaces": [
         "packages/scratch-svg-renderer",
@@ -10615,6 +10615,56 @@
         "typescript": ">=4"
       }
     },
+    "node_modules/coveralls": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.1.tgz",
+      "integrity": "sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "js-yaml": "^3.13.1",
+        "lcov-parse": "^1.0.0",
+        "log-driver": "^1.2.7",
+        "minimist": "^1.2.5",
+        "request": "^2.88.2"
+      },
+      "bin": {
+        "coveralls": "bin/coveralls.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/coveralls/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/coveralls/node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
     "node_modules/cpx": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/cpx/-/cpx-1.5.0.tgz",
@@ -13347,9 +13397,9 @@
       }
     },
     "node_modules/eslint-plugin-react": {
-      "version": "7.37.4",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz",
-      "integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==",
+      "version": "7.37.5",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
+      "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -13363,7 +13413,7 @@
         "hasown": "^2.0.2",
         "jsx-ast-utils": "^2.4.1 || ^3.0.0",
         "minimatch": "^3.1.2",
-        "object.entries": "^1.1.8",
+        "object.entries": "^1.1.9",
         "object.fromentries": "^2.0.8",
         "object.values": "^1.2.1",
         "prop-types": "^15.8.1",
@@ -18933,12 +18983,12 @@
       }
     },
     "node_modules/isomorphic-dompurify/node_modules/whatwg-url": {
-      "version": "14.1.1",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz",
-      "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==",
+      "version": "14.2.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
+      "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
       "license": "MIT",
       "dependencies": {
-        "tr46": "^5.0.0",
+        "tr46": "^5.1.0",
         "webidl-conversions": "^7.0.0"
       },
       "engines": {
@@ -27835,15 +27885,16 @@
       }
     },
     "node_modules/object.entries": {
-      "version": "1.1.8",
-      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
-      "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
+      "version": "1.1.9",
+      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
+      "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "call-bind": "^1.0.7",
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
         "define-properties": "^1.2.1",
-        "es-object-atoms": "^1.0.0"
+        "es-object-atoms": "^1.1.1"
       },
       "engines": {
         "node": ">= 0.4"
@@ -28703,9 +28754,9 @@
       "license": "MIT"
     },
     "node_modules/picocolors": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
-      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+      "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
       "license": "ISC"
     },
     "node_modules/picomatch": {
@@ -31755,9 +31806,9 @@
       }
     },
     "node_modules/scratch-audio": {
-      "version": "2.0.110",
-      "resolved": "https://registry.npmjs.org/scratch-audio/-/scratch-audio-2.0.110.tgz",
-      "integrity": "sha512-bIRkCJZ2pCtT1DVNjIKdwzPxc9q8858gJwwtWQcsQcKT0yeXNpjdr8w+2vtT+w4KUGafpRMkid2NzdfakU66YA==",
+      "version": "2.0.119",
+      "resolved": "https://registry.npmjs.org/scratch-audio/-/scratch-audio-2.0.119.tgz",
+      "integrity": "sha512-s+cHLFDYETPEXBz2dMXgQNB0hVlIB2bnnAl3LqYDyHkMqCUP2pEpCm0d+JP4pu+cRS2RJ8gDYfdc7zAEoujfVA==",
       "license": "AGPL-3.0-only",
       "dependencies": {
         "audio-context": "^1.0.1",
@@ -31766,9 +31817,9 @@
       }
     },
     "node_modules/scratch-blocks": {
-      "version": "1.1.206",
-      "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-1.1.206.tgz",
-      "integrity": "sha512-pjry8XGFlP2Gm3VJEuz7983oJE3fp2Gd1AzLDGaQSV8hDcAISzEd5GF0PoTZ2qQStp5G4b3eK/Xs9M+LEKmuJw==",
+      "version": "1.1.209",
+      "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-1.1.209.tgz",
+      "integrity": "sha512-jovPd8X79zf8QqApn9onIiDvv0n1rZ561Q+K2DXg6inM6IObVwkbbuEH4W8ZLsmAcRX8FriQ7zInyhaufd3EDw==",
       "license": "Apache-2.0",
       "dependencies": {
         "exports-loader": "^0.7.0",
@@ -31828,9 +31879,9 @@
       }
     },
     "node_modules/scratch-l10n": {
-      "version": "5.0.184",
-      "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-5.0.184.tgz",
-      "integrity": "sha512-3fkXrec/GLAXjBMTzEjgy+i87T3SCIR/efwxxFgmWBfy6K8K8HS9lTnLNuhprkIwSirD4BoO2+zJA//zsj6haw==",
+      "version": "5.0.198",
+      "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-5.0.198.tgz",
+      "integrity": "sha512-XpJIRGQinykaLEhjO+7bQLPmmunXd7ZN/6QAvP2AItb6QY5mJqhoaWvDZ9lR9e2n6vh8EOxdWabhchEKDEpCiA==",
       "license": "AGPL-3.0-only",
       "dependencies": {
         "@transifex/api": "4.3.0",
@@ -31843,9 +31894,9 @@
       }
     },
     "node_modules/scratch-paint": {
-      "version": "3.0.196",
-      "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-3.0.196.tgz",
-      "integrity": "sha512-iOGtyynYpe13zZv4j3JupyqJnK3bdt456+XR+Vwqc3lg9puwmamdsNvE/MU2uEog2w7k1E05OKe9Xa8mQPoE5Q==",
+      "version": "3.0.207",
+      "resolved": "https://registry.npmjs.org/scratch-paint/-/scratch-paint-3.0.207.tgz",
+      "integrity": "sha512-jI/rhGPaXxG1K3nKzaLFG5qLic+spmJOa4yJPs3ydCGCSyWunUghhReCX96d4SGS8TtzbTskU+f0FcKhCyJMag==",
       "license": "AGPL-3.0-only",
       "dependencies": {
         "@scratch/paper": "^0.11.20221201200345",
@@ -31917,17 +31968,17 @@
       }
     },
     "node_modules/scratch-render-fonts": {
-      "version": "1.0.180",
-      "resolved": "https://registry.npmjs.org/scratch-render-fonts/-/scratch-render-fonts-1.0.180.tgz",
-      "integrity": "sha512-JB3kt/lHjMxXmfYvH/DEAAI2PDqHm91ACo9esHMvzDK9ZYCw/WEsBQdy2qPhdvIcARCxRyTgGq/Jh1HD1uiTdw==",
+      "version": "1.0.182",
+      "resolved": "https://registry.npmjs.org/scratch-render-fonts/-/scratch-render-fonts-1.0.182.tgz",
+      "integrity": "sha512-T8oNXeFippbp5OK65EeFB/zheVN7e1GR2xKDSRH+IEU9bD0nsLC+WwIBje3KgpofvIMP3sKEvkRg0ZHBH3TO/Q==",
       "dependencies": {
         "base64-loader": "^1.0.0"
       }
     },
     "node_modules/scratch-sb1-converter": {
-      "version": "2.0.99",
-      "resolved": "https://registry.npmjs.org/scratch-sb1-converter/-/scratch-sb1-converter-2.0.99.tgz",
-      "integrity": "sha512-koyiA6xVFuJu6eGWFVACEy3sIjYJgeaUEgdmvZszlaDWuRXZhaAbnI1Q0TjtViaRzQub8HZvh9h9GkQ50tCvag==",
+      "version": "2.0.107",
+      "resolved": "https://registry.npmjs.org/scratch-sb1-converter/-/scratch-sb1-converter-2.0.107.tgz",
+      "integrity": "sha512-DpupSyhWJhE5pnXYP5mHgtFisWLHixBYup0CyXCUbEGzsiNv9II+u6JhWh082larI5UDLDMdJKG9dWKCB7+U9Q==",
       "license": "AGPL-3.0-only",
       "dependencies": {
         "js-md5": "^0.7.3",
@@ -31954,9 +32005,9 @@
       }
     },
     "node_modules/scratch-storage": {
-      "version": "4.0.95",
-      "resolved": "https://registry.npmjs.org/scratch-storage/-/scratch-storage-4.0.95.tgz",
-      "integrity": "sha512-rj9f+Y5k1TEMfULRk4t6bBP0kD298CmYvYoTEetgFfI/o45+iF8BtRy/Incamf4XaMhebzfVuHp/LbMQxBnpHA==",
+      "version": "4.0.106",
+      "resolved": "https://registry.npmjs.org/scratch-storage/-/scratch-storage-4.0.106.tgz",
+      "integrity": "sha512-QjzF2dXuS+YEZW+cx0No3Ite1ig0DFiI8akEyH5wdgGyAvfaqsxMx24ITnMjtdtR3s+HcFODwWpDO2f0k8UZGg==",
       "license": "AGPL-3.0-only",
       "dependencies": {
         "@babel/runtime": "^7.21.0",
@@ -38935,13 +38986,13 @@
     },
     "packages/scratch-gui": {
       "name": "@scratch/scratch-gui",
-      "version": "11.0.0",
+      "version": "11.1.0",
       "license": "AGPL-3.0-only",
       "dependencies": {
         "@microbit/microbit-universal-hex": "0.2.2",
-        "@scratch/scratch-render": "11.0.0",
-        "@scratch/scratch-svg-renderer": "11.0.0",
-        "@scratch/scratch-vm": "11.0.0",
+        "@scratch/scratch-render": "11.1.0",
+        "@scratch/scratch-svg-renderer": "11.1.0",
+        "@scratch/scratch-vm": "11.1.0",
         "arraybuffer-loader": "1.0.8",
         "autoprefixer": "9.8.8",
         "balance-text": "3.3.1",
@@ -38990,12 +39041,12 @@
         "react-virtualized": "9.22.6",
         "react-visibility-sensor": "5.0.2",
         "redux-throttle": "0.1.1",
-        "scratch-audio": "2.0.110",
-        "scratch-blocks": "1.1.206",
-        "scratch-l10n": "5.0.184",
-        "scratch-paint": "3.0.196",
-        "scratch-render-fonts": "1.0.180",
-        "scratch-storage": "4.0.95",
+        "scratch-audio": "2.0.119",
+        "scratch-blocks": "1.1.209",
+        "scratch-l10n": "5.0.198",
+        "scratch-paint": "3.0.207",
+        "scratch-render-fonts": "1.0.182",
+        "scratch-storage": "4.0.106",
         "startaudiocontext": "1.2.1",
         "style-loader": "4.0.0",
         "text-encoding": "0.7.0",
@@ -39027,7 +39078,7 @@
         "eslint-import-resolver-webpack": "0.11.1",
         "eslint-plugin-import": "2.31.0",
         "eslint-plugin-jest": "22.21.0",
-        "eslint-plugin-react": "7.37.4",
+        "eslint-plugin-react": "7.37.5",
         "file-loader": "6.2.0",
         "gh-pages": "3.2.3",
         "html-webpack-plugin": "5.6.3",
@@ -39502,10 +39553,10 @@
     },
     "packages/scratch-render": {
       "name": "@scratch/scratch-render",
-      "version": "11.0.0",
+      "version": "11.1.0",
       "license": "AGPL-3.0-only",
       "dependencies": {
-        "@scratch/scratch-svg-renderer": "11.0.0",
+        "@scratch/scratch-svg-renderer": "11.1.0",
         "grapheme-breaker": "0.3.2",
         "hull.js": "0.2.10",
         "ify-loader": "1.1.0",
@@ -39519,7 +39570,7 @@
         "@babel/eslint-parser": "7.27.0",
         "@babel/polyfill": "7.12.1",
         "@babel/preset-env": "7.26.9",
-        "@scratch/scratch-vm": "11.0.0",
+        "@scratch/scratch-vm": "11.1.0",
         "babel-loader": "9.2.1",
         "copy-webpack-plugin": "6.4.1",
         "docdash": "0.4.0",
@@ -39530,9 +39581,9 @@
         "jsdoc": "3.6.11",
         "json": "9.0.6",
         "playwright-chromium": "1.51.1",
-        "scratch-render-fonts": "1.0.180",
+        "scratch-render-fonts": "1.0.182",
         "scratch-semantic-release-config": "3.0.0",
-        "scratch-storage": "4.0.95",
+        "scratch-storage": "4.0.106",
         "scratch-webpack-configuration": "3.0.0",
         "semantic-release": "19.0.5",
         "tap": "16.3.10",
@@ -39674,7 +39725,7 @@
     },
     "packages/scratch-svg-renderer": {
       "name": "@scratch/scratch-svg-renderer",
-      "version": "11.0.0",
+      "version": "11.1.0",
       "license": "AGPL-3.0-only",
       "dependencies": {
         "base64-js": "1.5.1",
@@ -39698,7 +39749,7 @@
         "json": "9.0.6",
         "mkdirp": "2.1.6",
         "rimraf": "3.0.2",
-        "scratch-render-fonts": "1.0.180",
+        "scratch-render-fonts": "1.0.182",
         "scratch-semantic-release-config": "3.0.0",
         "scratch-webpack-configuration": "3.0.0",
         "semantic-release": "19.0.5",
@@ -39747,11 +39798,11 @@
     },
     "packages/scratch-vm": {
       "name": "@scratch/scratch-vm",
-      "version": "11.0.0",
+      "version": "11.1.0",
       "license": "AGPL-3.0-only",
       "dependencies": {
-        "@scratch/scratch-render": "11.0.0",
-        "@scratch/scratch-svg-renderer": "11.0.0",
+        "@scratch/scratch-render": "11.1.0",
+        "@scratch/scratch-svg-renderer": "11.1.0",
         "@vernier/godirect": "1.8.3",
         "arraybuffer-loader": "1.0.8",
         "atob": "2.1.2",
@@ -39764,10 +39815,10 @@
         "immutable": "3.8.2",
         "jszip": "3.10.1",
         "minilog": "3.1.0",
-        "scratch-audio": "2.0.110",
+        "scratch-audio": "2.0.119",
         "scratch-parser": "6.0.0",
-        "scratch-sb1-converter": "2.0.99",
-        "scratch-storage": "4.0.95",
+        "scratch-sb1-converter": "2.0.107",
+        "scratch-storage": "4.0.106",
         "scratch-translate-extension-languages": "1.0.7",
         "text-encoding": "0.7.0",
         "uuid": "8.3.2",
@@ -39792,9 +39843,9 @@
         "jsdoc": "3.6.11",
         "json": "^9.0.4",
         "pngjs": "3.4.0",
-        "scratch-blocks": "1.1.206",
-        "scratch-l10n": "5.0.184",
-        "scratch-render-fonts": "1.0.180",
+        "scratch-blocks": "1.1.209",
+        "scratch-l10n": "5.0.198",
+        "scratch-render-fonts": "1.0.182",
         "scratch-semantic-release-config": "3.0.0",
         "scratch-webpack-configuration": "3.0.0",
         "script-loader": "0.7.2",
diff --git a/package.json b/package.json
index a061ab3b1f..7cd9557b1e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "scratch-editor",
-  "version": "11.0.0",
+  "version": "11.1.0",
   "private": "true",
   "description": "Scratch editor mono-repository",
   "author": "Scratch Foundation",
diff --git a/packages/scratch-gui/package.json b/packages/scratch-gui/package.json
index e0a331a2a8..e5d1d645a5 100644
--- a/packages/scratch-gui/package.json
+++ b/packages/scratch-gui/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@scratch/scratch-gui",
-  "version": "11.0.0",
+  "version": "11.1.0",
   "description": "Graphical User Interface for creating and running Scratch 3.0 projects",
   "author": "Massachusetts Institute of Technology",
   "license": "AGPL-3.0-only",
@@ -16,6 +16,18 @@
       "types": "./dist/types/index.d.ts",
       "default": "./dist/scratch-gui.js"
     },
+    "./costumes": {
+      "default": "./src/lib/libraries/costumes.json"
+    },
+    "./sprites": {
+      "default": "./src/lib/libraries/sprites.json"
+    },
+    "./sounds": {
+      "default": "./src/lib/libraries/sounds.json"
+    },
+    "./backdrops": {
+      "default": "./src/lib/libraries/backdrops.json"
+    },
     "./standalone": {
       "types": "./dist/types/index-standalone.d.ts",
       "default": "./dist/scratch-gui-standalone.js"
@@ -43,9 +55,9 @@
   },
   "dependencies": {
     "@microbit/microbit-universal-hex": "0.2.2",
-    "@scratch/scratch-render": "11.0.0",
-    "@scratch/scratch-svg-renderer": "11.0.0",
-    "@scratch/scratch-vm": "11.0.0",
+    "@scratch/scratch-render": "11.1.0",
+    "@scratch/scratch-svg-renderer": "11.1.0",
+    "@scratch/scratch-vm": "11.1.0",
     "arraybuffer-loader": "1.0.8",
     "autoprefixer": "9.8.8",
     "balance-text": "3.3.1",
@@ -94,12 +106,12 @@
     "react-virtualized": "9.22.6",
     "react-visibility-sensor": "5.0.2",
     "redux-throttle": "0.1.1",
-    "scratch-audio": "2.0.110",
-    "scratch-blocks": "1.1.206",
-    "scratch-l10n": "5.0.184",
-    "scratch-paint": "3.0.196",
-    "scratch-render-fonts": "1.0.180",
-    "scratch-storage": "4.0.95",
+    "scratch-audio": "2.0.119",
+    "scratch-blocks": "1.1.209",
+    "scratch-l10n": "5.0.198",
+    "scratch-paint": "3.0.207",
+    "scratch-render-fonts": "1.0.182",
+    "scratch-storage": "4.0.106",
     "startaudiocontext": "1.2.1",
     "style-loader": "4.0.0",
     "to-style": "1.3.3",
@@ -137,7 +149,7 @@
     "eslint-import-resolver-webpack": "0.11.1",
     "eslint-plugin-import": "2.31.0",
     "eslint-plugin-jest": "22.21.0",
-    "eslint-plugin-react": "7.37.4",
+    "eslint-plugin-react": "7.37.5",
     "file-loader": "6.2.0",
     "gh-pages": "3.2.3",
     "html-webpack-plugin": "5.6.3",
diff --git a/packages/scratch-gui/src/components/cards/cards.jsx b/packages/scratch-gui/src/components/cards/cards.jsx
index 46a9549e40..ec0111e1ad 100644
--- a/packages/scratch-gui/src/components/cards/cards.jsx
+++ b/packages/scratch-gui/src/components/cards/cards.jsx
@@ -18,8 +18,6 @@ import closeIcon from './icon--close.svg';
 import {translateVideo} from '../../lib/libraries/decks/translate-video.js';
 import {translateImage} from '../../lib/libraries/decks/translate-image.js';
 
-import {PLATFORM} from '../../lib/platform.js';
-
 const CardHeader = ({onCloseCards, onShrinkExpandCards, onShowAll, totalSteps, step, expanded}) => (
     <div className={expanded ? styles.headerButtons : classNames(styles.headerButtons, styles.headerButtonsHidden)}>
         <div
@@ -151,7 +149,7 @@ VideoStep.propTypes = {
     video: PropTypes.string.isRequired
 };
 
-const ImageStep = ({title, image, platform}) => (<Fragment>
+const ImageStep = ({title, image}) => (<Fragment>
     <div className={styles.stepTitle}>
         {title}
     </div>
@@ -160,7 +158,7 @@ const ImageStep = ({title, image, platform}) => (<Fragment>
             className={styles.stepImage}
             draggable={false}
             key={image} /* Use src as key to prevent hanging around on slow connections */
-            src={platform === PLATFORM.ANDROID ? `file:///android_asset/www${image}` : image}
+            src={image}
         />
     </div>
 </Fragment>
@@ -168,8 +166,7 @@ const ImageStep = ({title, image, platform}) => (<Fragment>
 
 ImageStep.propTypes = {
     image: PropTypes.string.isRequired,
-    title: PropTypes.node.isRequired,
-    platform: PropTypes.string
+    title: PropTypes.node.isRequired
 };
 
 const NextPrevButtons = ({isRtl, onNextStep, onPrevStep, expanded}) => (
@@ -220,7 +217,7 @@ CardHeader.propTypes = {
     totalSteps: PropTypes.number
 };
 
-const PreviewsStep = ({deckIds, content, onActivateDeckFactory, onShowAll, platform}) => (
+const PreviewsStep = ({deckIds, content, onActivateDeckFactory, onShowAll}) => (
     <Fragment>
         <div className={styles.stepTitle}>
             <FormattedMessage
@@ -239,7 +236,7 @@ const PreviewsStep = ({deckIds, content, onActivateDeckFactory, onShowAll, platf
                     <img
                         className={styles.deckImage}
                         draggable={false}
-                        src={platform === PLATFORM.ANDROID ? `file:///android_asset/www${content[id].img}` : content[id].img}
+                        src={content[id].img}
                     />
                     <div className={styles.deckName}>{content[id].name}</div>
                 </div>
@@ -275,8 +272,7 @@ PreviewsStep.propTypes = {
     }).isRequired,
     deckIds: PropTypes.arrayOf(PropTypes.string).isRequired,
     onActivateDeckFactory: PropTypes.func.isRequired,
-    onShowAll: PropTypes.func.isRequired,
-    platform: PropTypes.string
+    onShowAll: PropTypes.func.isRequired
 };
 
 const Cards = props => {
@@ -295,10 +291,9 @@ const Cards = props => {
         onShowAll,
         onNextStep,
         onPrevStep,
-        showVideos,
         step,
         expanded,
-        platform,
+        showVideos,
         ...posProps
     } = props;
     let {x, y} = posProps;
@@ -362,28 +357,26 @@ const Cards = props => {
                                     deckIds={steps[step].deckIds}
                                     onActivateDeckFactory={onActivateDeckFactory}
                                     onShowAll={onShowAll}
-                                    platform={platform}
                                 />
                             ) : (
                                 steps[step].video ? (
-                                    (platform === PLATFORM.WEB || platform === PLATFORM.ANDROID) && showVideos ? (
-                                        <VideoStep
-                                            dragging={dragging}
-                                            expanded={expanded}
-                                            video={translateVideo(steps[step].video, locale)}
-                                        />
-                                    ) : ( // Else show the deck image and title
-                                        <ImageStep
-                                            image={content[activeDeckId].img}
-                                            title={content[activeDeckId].name}
-                                            platform={platform}
-                                        />
-                                    )
+                                    showVideos ?
+                                        (
+                                            <VideoStep
+                                                dragging={dragging}
+                                                expanded={expanded}
+                                                video={translateVideo(steps[step].video, locale)}
+                                            />
+                                        ) : (
+                                            <ImageStep
+                                                image={content[activeDeckId].img}
+                                                title={content[activeDeckId].name}
+                                            />
+                                        )
                                 ) : (
                                     <ImageStep
                                         image={translateImage(steps[step].image, locale)}
                                         title={steps[step].title}
-                                        platform={platform}
                                     />
                                 )
                             )}
@@ -430,16 +423,11 @@ Cards.propTypes = {
     onShrinkExpandCards: PropTypes.func.isRequired,
     onStartDrag: PropTypes.func,
     showVideos: PropTypes.bool,
-    platform: PropTypes.string,
     step: PropTypes.number.isRequired,
     x: PropTypes.number,
     y: PropTypes.number
 };
 
-Cards.defaultProps = {
-    showVideos: true
-};
-
 export {
     Cards as default,
     // Others exported for testability
diff --git a/packages/scratch-gui/src/components/debug-modal/debug-modal.css b/packages/scratch-gui/src/components/debug-modal/debug-modal.css
index ad02262ea7..c7e624ebae 100644
--- a/packages/scratch-gui/src/components/debug-modal/debug-modal.css
+++ b/packages/scratch-gui/src/components/debug-modal/debug-modal.css
@@ -6,7 +6,7 @@
     left: 0;
     right: 0;
     bottom: 0;
-    background-color: 'transparent';
+    background-color: transparent;
     display: flex;
     justify-content: center;
     align-items: center;
diff --git a/packages/scratch-gui/src/components/debug-modal/sections/messages.ts b/packages/scratch-gui/src/components/debug-modal/sections/messages.js
similarity index 98%
rename from packages/scratch-gui/src/components/debug-modal/sections/messages.ts
rename to packages/scratch-gui/src/components/debug-modal/sections/messages.js
index e2f0e7c896..9669d12835 100644
--- a/packages/scratch-gui/src/components/debug-modal/sections/messages.ts
+++ b/packages/scratch-gui/src/components/debug-modal/sections/messages.js
@@ -1,5 +1,8 @@
 import {defineMessages} from 'react-intl';
 
+// TODO: These are not detected by the `i18n:src` script if the file is with `.ts` extension.
+// This issue might be affecting other .ts files as well.
+// https://scratchfoundation.atlassian.net/browse/UEPR-221
 export const messages = defineMessages({
     readAloudTitle: {
         id: 'gui.debugModal.readAloud.title',
diff --git a/packages/scratch-gui/src/components/debug-modal/sections/sections.jsx b/packages/scratch-gui/src/components/debug-modal/sections/sections.jsx
index 6295ddbabf..108a76bafb 100644
--- a/packages/scratch-gui/src/components/debug-modal/sections/sections.jsx
+++ b/packages/scratch-gui/src/components/debug-modal/sections/sections.jsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import {FormattedMessage} from 'react-intl';
-import {messages} from './messages.ts';
+import {messages} from './messages.js';
 
 import addSoundCheckpoints from '../icons/icon--add-sound-checkpoints.svg';
 import askForHelp from '../icons/icon--ask-for-help.svg';
diff --git a/packages/scratch-gui/src/components/gui/gui.jsx b/packages/scratch-gui/src/components/gui/gui.jsx
index d192b20c48..5ca60fb42d 100644
--- a/packages/scratch-gui/src/components/gui/gui.jsx
+++ b/packages/scratch-gui/src/components/gui/gui.jsx
@@ -1,7 +1,7 @@
 import classNames from 'classnames';
 import omit from 'lodash.omit';
 import PropTypes from 'prop-types';
-import React, {useEffect} from 'react';
+import React, {useEffect, useCallback} from 'react';
 import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl';
 import {connect} from 'react-redux';
 import MediaQuery from 'react-responsive';
@@ -43,6 +43,7 @@ import costumesIcon from './icon--costumes.svg';
 import soundsIcon from './icon--sounds.svg';
 import DebugModal from '../debug-modal/debug-modal.jsx';
 import {setPlatform} from '../../reducers/platform.js';
+import {PLATFORM} from '../../lib/platform.js';
 
 const messages = defineMessages({
     addExtension: {
@@ -87,6 +88,8 @@ const GUIComponent = props => {
         costumeLibraryVisible,
         costumesTabVisible,
         debugModalVisible,
+        onDebugModalClose,
+        onTutorialSelect,
         enableCommunity,
         intl,
         isCreating,
@@ -158,6 +161,13 @@ const GUIComponent = props => {
         tabSelected: classNames(tabStyles.reactTabsTabSelected, styles.isSelected)
     };
 
+    const onCloseDebugModal = useCallback(() => {
+        if (onDebugModalClose) {
+            onDebugModalClose();
+        }
+        onRequestCloseDebugModal();
+    }, [onDebugModalClose, onRequestCloseDebugModal]);
+
     if (isRendererSupported === null) {
         isRendererSupported = Renderer.isSupported();
     }
@@ -205,7 +215,10 @@ const GUIComponent = props => {
                     <WebGlModal isRtl={isRtl} />
                 )}
                 {tipsLibraryVisible ? (
-                    <TipsLibrary hideTutorialProjects={hideTutorialProjects} />
+                    <TipsLibrary
+                        hideTutorialProjects={hideTutorialProjects}
+                        onTutorialSelect={onTutorialSelect}
+                    />
                 ) : null}
                 {cardsVisible ? (
                     <Cards />
@@ -227,7 +240,7 @@ const GUIComponent = props => {
                 ) : null}
                 {<DebugModal
                     isOpen={debugModalVisible}
-                    onClose={onRequestCloseDebugModal}
+                    onClose={onCloseDebugModal}
                 />}
                 {backdropLibraryVisible ? (
                     <BackdropLibrary
@@ -432,6 +445,8 @@ GUIComponent.propTypes = {
     costumeLibraryVisible: PropTypes.bool,
     costumesTabVisible: PropTypes.bool,
     debugModalVisible: PropTypes.bool,
+    onDebugModalClose: PropTypes.func,
+    onTutorialSelect: PropTypes.func,
     enableCommunity: PropTypes.bool,
     intl: intlShape.isRequired,
     isCreating: PropTypes.bool,
@@ -466,7 +481,7 @@ GUIComponent.propTypes = {
     onTelemetryModalOptIn: PropTypes.func,
     onTelemetryModalOptOut: PropTypes.func,
     onToggleLoginOpen: PropTypes.func,
-    platform: PropTypes.string,
+    platform: PropTypes.oneOf(Object.keys(PLATFORM)),
     renderLogin: PropTypes.func,
     showComingSoon: PropTypes.bool,
     soundsTabVisible: PropTypes.bool,
diff --git a/packages/scratch-gui/src/components/library-item/library-item.jsx b/packages/scratch-gui/src/components/library-item/library-item.jsx
index 3affe1e773..fc43cea89e 100644
--- a/packages/scratch-gui/src/components/library-item/library-item.jsx
+++ b/packages/scratch-gui/src/components/library-item/library-item.jsx
@@ -41,7 +41,6 @@ class LibraryItemComponent extends React.PureComponent {
                         <ScratchImage
                             className={styles.featuredImage}
                             imageSource={this.props.iconSource}
-                            platform={this.props.platform}
                         />
                     ) : null}
                 </div>
@@ -134,7 +133,6 @@ class LibraryItemComponent extends React.PureComponent {
                         <ScratchImage
                             className={styles.libraryItemImage}
                             imageSource={this.props.iconSource}
-                            platform={this.props.platform}
                         />
                     </Box>
                 </Box>
@@ -172,7 +170,6 @@ LibraryItemComponent.propTypes = {
         PropTypes.string,
         PropTypes.node
     ]),
-    platform: PropTypes.string,
     onBlur: PropTypes.func.isRequired,
     onClick: PropTypes.func.isRequired,
     onFocus: PropTypes.func.isRequired,
diff --git a/packages/scratch-gui/src/components/library/library.jsx b/packages/scratch-gui/src/components/library/library.jsx
index 4df4d51c39..54a5f0ce86 100644
--- a/packages/scratch-gui/src/components/library/library.jsx
+++ b/packages/scratch-gui/src/components/library/library.jsx
@@ -73,21 +73,35 @@ const getAssetTypeForFileExtension = function (fileExtension) {
 };
 
 /**
- * Figure out an `imageSource` (URI or asset ID & type) for a library item's icon.
+ * Figure out one or more icon(s) for a library item.
+ * If it's an animated thumbnail, this will return an array of `imageSource`.
+ * Otherwise it'll return just one `imageSource`.
  * @param {object} item - either a library item or one of a library item's costumes.
- * @returns {object} - an `imageSource` ready to be passed to a `ScratchImage`.
+ *   The latter is used internally as part of processing an animated thumbnail.
+ * @returns {LibraryItem.PropTypes.icons} - an `imageSource` or array of them, ready for `LibraryItem` & `ScratchImage`
  */
-const getItemImageSource = function (item) {
+const getItemIcons = function (item) {
+    const costumes = (item.json && item.json.costumes) || item.costumes;
+    if (costumes) {
+        return costumes.map(getItemIcons);
+    }
+
     if (item.rawURL) {
         return {
             uri: item.rawURL
         };
     }
 
-    // TODO: adjust libraries to be more storage-friendly; don't use split() here.
-    const md5 = item.costumes ? item.costumes[0].md5ext : item.md5ext;
-    if (md5) {
-        const [assetId, fileExtension] = md5.split('.');
+    if (item.assetId && item.dataFormat) {
+        return {
+            assetId: item.assetId,
+            assetType: getAssetTypeForFileExtension(item.dataFormat)
+        };
+    }
+
+    const md5ext = item.md5ext || item.md5 || item.baseLayerMD5;
+    if (md5ext) {
+        const [assetId, fileExtension] = md5ext.split('.');
         return {
             assetId: assetId,
             assetType: getAssetTypeForFileExtension(fileExtension)
@@ -233,9 +247,7 @@ class LibraryComponent extends React.Component {
     }
     renderElement (data) {
         const key = this.constructKey(data);
-        const iconSource = getItemImageSource(data);
-        const icons = data.json && data.json.costumes.map(getItemImageSource);
-
+        const icons = getItemIcons(data);
         return (<LibraryItem
             bluetoothRequired={data.bluetoothRequired}
             collaborator={data.collaborator}
@@ -244,9 +256,6 @@ class LibraryComponent extends React.Component {
             extensionId={data.extensionId}
             featured={data.featured}
             hidden={data.hidden}
-            iconMd5={data.costumes ? data.costumes[0].md5ext : data.md5ext}
-            iconRawURL={data.rawURL}
-            iconSource={iconSource}
             icons={icons}
             id={key}
             insetIconURL={data.insetIconURL}
@@ -265,7 +274,12 @@ class LibraryComponent extends React.Component {
             return data.map(item => this.renderElement(item));
         }
 
-        const dataByCategory = Object.groupBy(data, el => el.category);
+        // Object.groupBy is not available on older versions of javascript
+        const dataByCategory = data.reduce((acc, el) => {
+            acc[el.category] = acc[el.category] || [];
+            acc[el.category].push(el);
+            return acc;
+        }, {});
         const categoriesOrder = Object.values(CATEGORIES);
 
         return Object.entries(dataByCategory)
diff --git a/packages/scratch-gui/src/components/menu-bar/menu-bar.jsx b/packages/scratch-gui/src/components/menu-bar/menu-bar.jsx
index 0333b3650b..5563c69818 100644
--- a/packages/scratch-gui/src/components/menu-bar/menu-bar.jsx
+++ b/packages/scratch-gui/src/components/menu-bar/menu-bar.jsx
@@ -73,6 +73,7 @@ import {
 } from '../../reducers/menus';
 
 import collectMetadata from '../../lib/collect-metadata';
+import {PLATFORM} from '../../lib/platform';
 
 import styles from './menu-bar.css';
 
@@ -87,6 +88,7 @@ import editIcon from './icon--edit.svg';
 import debugIcon from '../debug-modal/icons/icon--debug.svg';
 
 import scratchLogo from './scratch-logo.svg';
+import scratchLogoAndroid from './scratch-logo-android.svg';
 import ninetiesLogo from './nineties_logo.svg';
 import catLogo from './cat_logo.svg';
 import prehistoricLogo from './prehistoric-logo.svg';
@@ -109,6 +111,8 @@ const ariaMessages = defineMessages({
     }
 });
 
+const getScratchLogo = platform => (platform === PLATFORM.ANDROID ? scratchLogoAndroid : scratchLogo);
+
 const MenuBarItemTooltip = ({
     children,
     className,
@@ -271,7 +275,7 @@ class MenuBar extends React.Component {
             } else if (mode === '220022BC') {
                 document.getElementById('logo_img').src = prehistoricLogo;
             } else {
-                document.getElementById('logo_img').src = this.props.logo;
+                document.getElementById('logo_img').src = getScratchLogo(this.props.platform);
             }
 
             this.props.onSetTimeTravelMode(mode);
@@ -443,7 +447,7 @@ class MenuBar extends React.Component {
                                     [styles.clickable]: typeof this.props.onClickLogo !== 'undefined'
                                 })}
                                 draggable={false}
-                                src={this.props.logo}
+                                src={getScratchLogo(this.props.platform)}
                                 onClick={this.props.onClickLogo}
                             />
                         </div>
@@ -962,6 +966,7 @@ MenuBar.propTypes = {
     onShare: PropTypes.func,
     onStartSelectingFileUpload: PropTypes.func,
     onToggleLoginOpen: PropTypes.func,
+    platform: PropTypes.oneOf(Object.keys(PLATFORM)),
     projectTitle: PropTypes.string,
     renderLogin: PropTypes.func,
     settingsMenuOpen: PropTypes.bool,
@@ -1009,12 +1014,14 @@ const mapStateToProps = (state, ownProps) => {
         mode2020: isTimeTravel2020(state),
         modeNow: isTimeTravelNow(state),
 
+        platform: state.scratchGui.platform.platform,
+
         userOwnsProject: ownProps.userOwnsProject ?? (
             ownProps.authorUsername && user && (ownProps.authorUsername === user.username)
         ),
 
         accountMenuOptions: ownProps.accountMenuOptions ?? {
-            canHaveSession: sessionExists,
+            canHaveSession: sessionExists ?? false,
 
             canRegister: true,
             canLogin: true,
diff --git a/packages/scratch-gui/src/components/menu-bar/scratch-logo-android.svg b/packages/scratch-gui/src/components/menu-bar/scratch-logo-android.svg
new file mode 100644
index 0000000000..931b628ec8
--- /dev/null
+++ b/packages/scratch-gui/src/components/menu-bar/scratch-logo-android.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" viewBox="0 0 96 24.7"><style>.st0{fill:#fff}.st1{fill:#f9a83a}</style><switch><g><g><g><path d="M60.2 24.1c-.8.1-1.3.1-1.5.2-.4.2-1.3.4-2.4.4-1.4 0-2.7-.5-3.8-1.3h-.8c-.3 0-.5 0-.8-.1-1.1.4-2.1.4-2.7.4H48c-1.4.1-2.8-.2-4-.8-.6.2-1.1.3-1.7.3l-3.7.1c-1.7 0-3.2-.6-4.4-1.7-.5 0-1-.1-1.4-.2-.6.7-1.4 1.3-2.4 1.8-1.9.9-4 1-6 .2-.2-.1-.5-.2-.7-.3l-2.3.3h-.7c-.3.1-.5.3-.7.4-1.5.7-2.9.7-3.5.7H16c-1.7 0-3.4-.5-4.7-1.4-.4.1-.9.2-1.3.2-.9.6-2 1-3.2 1.1h-.4c-3.3 0-6-2.5-6.3-5.8v-.1c0-.5-.1-1.6 0-2.8 0-.6.1-1.5.1-1.7 0-.8.2-1.6.5-2.4-.2-.8-.1-1.6 0-2.4v-.3c.1-.7.3-2.1 1-3.5C3 3 5.4 1.5 8.1 1.5 9 1 9.9.8 10.9.8h.3c2 .1 3.8 1.1 4.9 2.7.9-.8 2-1.3 3.2-1.5 2.4-.3 4.4-.4 6.1-.1.9-.8 2.1-1.4 3.3-1.5l2.6-.4h.8c1.5 0 3 .6 4.2 1.6h.2l3.8-.1c1.6 0 3-.1 3.3-.1h.5c1.4 0 2.9.5 4 1.4 1.1-.8 2.4-1.2 3.8-1.2h1.3c1-.6 2.1-1 3.3-1l3.2-.1h.1c3.4 0 6.2 2.8 6.3 6.2 0 1.6-.5 3-1.5 4.2v2.9c.9 1 1.4 2.3 1.5 3.7.2 3.4-2.4 6.3-5.9 6.6z" class="st0"/></g><path d="M60 20.5c-1.3.1-2.1.2-2.3.3l-.1.1c-.3.1-.7.3-1.2.3-.6 0-1.3-.2-1.8-.7-.2-.2-.4-.4-.5-.6h-2.3c-.4 0-.8-.1-1.1-.3-.1.1-.3.1-.4.2-.8.4-1.5.4-2 .4h-.5c-1.5 0-2.7-.5-3.5-1.4-.5.5-1.2.8-1.9.8l-3.7.1c-1.3 0-2.5-1-2.7-2.2-.5.3-1 .5-1.6.5-.6 0-1.2-.2-1.7-.5-.1-.1-.2-.2-.3-.2-.3.2-.7.2-1.1.2H31c-.4 1.2-1.1 2-2.2 2.5-.5.2-1.1.4-1.6.4s-1.1-.1-1.6-.3c-.5-.2-.9-.5-1.2-.8-.2.1-.4.1-.6.2l-2.9.4h-.4c-.3 0-.5 0-.8-.1-.4.4-.9.6-1.3.8-.8.4-1.5.4-2 .4h-.5c-1.8 0-3.2-.8-4-1.9-.8.5-1.8.8-2.7.8h-.6c0 .1-.1.1-.1.2-.5.5-1.2.9-1.9.9h-.2c-1.4 0-2.6-1.1-2.7-2.6v-.1c0-.5-.1-1.4 0-2.4 0-.7.1-1.8.1-1.8 0-.7.3-1.3.7-1.8-.4-.8-.5-1.7-.3-2.7v-.2c.1-.6.2-1.5.6-2.4.7-1.3 2-2 3.5-2H9c.5-.4 1.1-.7 1.8-.7 1.5 0 2.7 1.3 2.7 2.8v1.1c.5-.2 1.1-.3 1.7-.3.3 0 .5 0 .8.1.4-.5 1-.8 1.6-.9.1-.2.2-.3.3-.5.4-.6 1.1-1 1.8-1.1.6-.1 1.8-.2 3.2-.2 1.6 0 2.9.2 3.9.7.3-1.1 1.1-1.9 2.3-2.1l2.6-.4h.4c.8 0 1.5.3 2 .9.2.2.5.6.6.9l.1.3c.5-.3 1-.5 1.6-.5l3.9-.1c1.9 0 3.6-.1 3.6-.2h.2c.7 0 1.5.3 2 .8.4.4.7.9.8 1.5h.2c.3 0 .5 0 .8.1.4-.5 1-.8 1.6-.9.5-.7 1.4-1.3 2.4-1.3h2.6c.5-.6 1.2-1 2.1-1h3.2c1.5 0 2.7 1.2 2.8 2.7 0 1.1-.6 2.1-1.5 2.5v6.1c.8.4 1.4 1.3 1.5 2.3.1 1.5-1.1 2.8-2.6 2.9z" class="st1"/><path d="M32.3 8.5l-.7 3.6 2-.3z" class="st1"/><path d="M8.4 12c-.7-.1-1.1-.6-.9-2v-.2c.2-1.2.3-1.5.9-1.5.2 0 .4.1.6.3.2.2.6.5.8 1.1.2.4.2.7.3 1v.4c0 .2.2.4.5.5.3.1.6-.2.7-.5 0 0 .2-3.8.2-3.9 0-.3-.3-.6-.6-.6s-.6.3-.6.6v1.1c-.5-.5-1.1-1-1.8-1C6.6 7 6.4 8.7 6.3 9.7v.2c-.2 1.9.4 3.1 1.9 3.4 1.6.3 2.7.6 2.7 1.6 0 .4-.2.8-.6 1.1-.4.4-1 .5-1.6.4-.2 0-.3-.1-.5-.1-.2-.1-.8-.4-1-.8-.1-.4-.2-.9-.2-1.2v-.2c0-.3-.3-.6-.6-.6s-.6.3-.6.6c0 0 0 1.2-.1 1.9-.1 1.2 0 2.1 0 2.2 0 .3.3.6.6.6s.6-.3.6-.6v-1.1c.4.3 1 .6 1.7.7.9.2 1.8-.1 2.5-.7.6-.5 1-1.3 1-2 0-2.5-2.5-2.9-3.7-3.1M25.2 10.3c-.1.1-.2.2-.4.3-.1.1-.4.2-.5.2l-.3.1c-.4.2-1 .3-1.6.4V8.5c1.6 0 3 .1 3.3.6v.2c0 .2-.2.6-.5 1m3.5 5.4c-.3-.1-.7.1-.8.4-.2.7-.4.7-.5.8-.1.1-.3 0-.6-.1 0 0-.1-.2-.2-.3-.1-.2-.2-1-.2-1.5 0-1.8-.4-2.8-.9-3.3.3-.2.6-.5.6-.5.7-1 .9-1.8.5-2.5-1-1.7-5.3-1.2-6.7-1-.3 0-.6.4-.5.7 0 .3.4.6.7.5.3 0 .6-.1.9-.1v2.8h-.3c-.3 0-.6.3-.6.6s.3.6.6.6h.3v3.5l-.8.1c-.3 0-.6.4-.5.7 0 .3.4.6.7.5l2.9-.4c.3 0 .6-.4.5-.7 0-.3-.4-.6-.7-.5l-.9.1v-3.5c.6-.1 1.1-.2 1.6-.4h.2c.2 0 .4.1.5.3.2.3.4.9.5 2.4 0 .3.1 1.5.3 2 .1.2.4.7.9.9.4.1.9.3 1.5 0 .5-.3.9-.6 1.1-1.5.4-.2.2-.5-.1-.6M50.5 13.8c-.3 0-.6.3-.6.6v.8c0 .3-.1.7-.2.8-.1.2-.2.3-.4.5-.1.1-.3.2-.5.3-.2.1-.3.1-.7.1h-.4c-1.6.1-1.8-1.2-1.8-1.5v-2.6c.1-1 .3-1.7.7-2 .3-.2.7-.1 1.4.1.8.3 1.3 1.2 1.4 1.2.1.2.4.3.7.3.3-.1.4-.3.4-.6V9.1c0-.3-.3-.6-.6-.6s-.6.3-.6.6v1.1c-.2-.2-.5-.3-.8-.5-.3-.2-1.5-.7-2.4-.1-.7.5-1.2 1.4-1.3 2.9v2.8c.1.9.8 2.7 3 2.7h.3c.4 0 .8 0 1.2-.2.3-.1.6-.3.9-.6.2-.2.3-.4.5-.7.2-.4.3-1.1.4-1.3v-1c0-.2-.3-.4-.6-.4M60.4 17.8c0-.3-.3-.6-.6-.6-.2 0-.5 0-.8.1 0-1 0-3.1-.1-9.9h.9c.3 0 .6-.3.6-.6s-.3-.6-.6-.6l-3.2.1c-.3 0-.6.3-.6.6s.3.6.6.6h1v4.2l-3.6.6V8.5h1c.3 0 .6-.3.6-.6s-.3-.6-.6-.6h-3.2c-.3 0-.6.3-.6.6s.3.6.6.6h1v8.1h-1c-.3 0-.6.3-.6.6s.3.6.6.6l3.3.1c.3 0 .6-.3.6-.6s-.3-.6-.6-.6h-1v-3.1l3.6-.6v4.6c-.8.2-1.4.2-1.7.6-.2.2-.2.6.1.8.2.2.5.1.9 0 .3-.2 1.5-.3 2.9-.4.3-.2.5-.5.5-.8" class="st0"/><path d="M31.6 12.1l.7-3.6 1.3 3.3-2 .3zm5.3 1c-.2.1-.5.2-1.1.5l-.8-1.9-2.3-5.5c0-.1-.1-.3-.2-.3-.1-.1-.3-.2-.5-.2l-2.6.3c-.3 0-.6.3-.5.7 0 .3.3.6.7.5 0 0 1-.1 1.8-.2-.2 1.1-1.1 5.6-1.4 7l-1.8-.1c-.3 0-.6.2-.6.6 0 .3.2.6.6.6l3 .1c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6l.1-.9 2.8-.5.6 1.5c-.5.3-.7.4-1 .7-.2.3-.1.6.1.8.3.2.7.1.9-.1.3-.4 1.4-.9 2.5-1.3.3-.1.5-.5.4-.8-.1-.2-.4-.4-.7-.3" class="st0"/><path d="M44.1 7s-1.8.1-3.8.2l-3.9.1c-.2 0-.3.1-.5.2-.1.1-.2.3-.1.5l.5 3c0 .3.4.6.7.5.3 0 .5-.3.5-.6 0 0-.2-1.6-.4-2.4h2.6v7.9h-1.3c-.3 0-.6.3-.6.6s.3.6.6.6l3.7-.1c.3 0 .6-.3.6-.6s-.3-.6-.6-.6h-1.2V8.4c1 0 1.9-.1 2.5-.1v1.2c0 .6.1.8.1.9.2.3.5.4.8.2.2-.1.3-.4.3-.6 0 0 0-1.4.1-2.2 0-.2 0-.3-.2-.5 0-.2-.2-.3-.4-.3M18.6 14.4c-.3 0-.6.3-.6.6V15.9c0 .2-.1.6-.2.8-.1.2-.2.3-.4.5-.1.1-.3.2-.5.3-.2.1-.3.1-.7.1h-.4c-1.6 0-1.8-1.2-1.8-1.5v-2.6c.1-1 .3-1.7.7-2 .3-.2.7-.1 1.4.1.8.3 1.4 1.2 1.4 1.2.1.2.4.3.7.3.3-.1.4-.3.4-.6V9.8c0-.3-.3-.6-.6-.6s-.6.3-.6.6v1.1c-.2-.2-.5-.4-.8-.5-.4-.2-1.5-.6-2.5-.1-.7.5-1.2 1.4-1.3 2.9V16c.1.9.8 2.7 3.1 2.7h.3c.4 0 .8 0 1.2-.2.3-.1.6-.3.9-.6.2-.2.3-.4.5-.7.2-.4.3-1.1.4-1.3v-1c0-.2-.3-.5-.6-.5" class="st0"/></g></g></switch>
+<g transform="translate(68,0)">
+<path fill="white" d="M9.984 20.016h-4.969v-8.016h-3l9.984-9 9.984 9h-3v8.016h-4.969v-6h-4.031v6z"></path>
+</g>
+</svg>
diff --git a/packages/scratch-gui/src/components/menu-bar/scratch-logo.svg b/packages/scratch-gui/src/components/menu-bar/scratch-logo.svg
index 931b628ec8..28b62731df 100644
--- a/packages/scratch-gui/src/components/menu-bar/scratch-logo.svg
+++ b/packages/scratch-gui/src/components/menu-bar/scratch-logo.svg
@@ -1,5 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" viewBox="0 0 96 24.7"><style>.st0{fill:#fff}.st1{fill:#f9a83a}</style><switch><g><g><g><path d="M60.2 24.1c-.8.1-1.3.1-1.5.2-.4.2-1.3.4-2.4.4-1.4 0-2.7-.5-3.8-1.3h-.8c-.3 0-.5 0-.8-.1-1.1.4-2.1.4-2.7.4H48c-1.4.1-2.8-.2-4-.8-.6.2-1.1.3-1.7.3l-3.7.1c-1.7 0-3.2-.6-4.4-1.7-.5 0-1-.1-1.4-.2-.6.7-1.4 1.3-2.4 1.8-1.9.9-4 1-6 .2-.2-.1-.5-.2-.7-.3l-2.3.3h-.7c-.3.1-.5.3-.7.4-1.5.7-2.9.7-3.5.7H16c-1.7 0-3.4-.5-4.7-1.4-.4.1-.9.2-1.3.2-.9.6-2 1-3.2 1.1h-.4c-3.3 0-6-2.5-6.3-5.8v-.1c0-.5-.1-1.6 0-2.8 0-.6.1-1.5.1-1.7 0-.8.2-1.6.5-2.4-.2-.8-.1-1.6 0-2.4v-.3c.1-.7.3-2.1 1-3.5C3 3 5.4 1.5 8.1 1.5 9 1 9.9.8 10.9.8h.3c2 .1 3.8 1.1 4.9 2.7.9-.8 2-1.3 3.2-1.5 2.4-.3 4.4-.4 6.1-.1.9-.8 2.1-1.4 3.3-1.5l2.6-.4h.8c1.5 0 3 .6 4.2 1.6h.2l3.8-.1c1.6 0 3-.1 3.3-.1h.5c1.4 0 2.9.5 4 1.4 1.1-.8 2.4-1.2 3.8-1.2h1.3c1-.6 2.1-1 3.3-1l3.2-.1h.1c3.4 0 6.2 2.8 6.3 6.2 0 1.6-.5 3-1.5 4.2v2.9c.9 1 1.4 2.3 1.5 3.7.2 3.4-2.4 6.3-5.9 6.6z" class="st0"/></g><path d="M60 20.5c-1.3.1-2.1.2-2.3.3l-.1.1c-.3.1-.7.3-1.2.3-.6 0-1.3-.2-1.8-.7-.2-.2-.4-.4-.5-.6h-2.3c-.4 0-.8-.1-1.1-.3-.1.1-.3.1-.4.2-.8.4-1.5.4-2 .4h-.5c-1.5 0-2.7-.5-3.5-1.4-.5.5-1.2.8-1.9.8l-3.7.1c-1.3 0-2.5-1-2.7-2.2-.5.3-1 .5-1.6.5-.6 0-1.2-.2-1.7-.5-.1-.1-.2-.2-.3-.2-.3.2-.7.2-1.1.2H31c-.4 1.2-1.1 2-2.2 2.5-.5.2-1.1.4-1.6.4s-1.1-.1-1.6-.3c-.5-.2-.9-.5-1.2-.8-.2.1-.4.1-.6.2l-2.9.4h-.4c-.3 0-.5 0-.8-.1-.4.4-.9.6-1.3.8-.8.4-1.5.4-2 .4h-.5c-1.8 0-3.2-.8-4-1.9-.8.5-1.8.8-2.7.8h-.6c0 .1-.1.1-.1.2-.5.5-1.2.9-1.9.9h-.2c-1.4 0-2.6-1.1-2.7-2.6v-.1c0-.5-.1-1.4 0-2.4 0-.7.1-1.8.1-1.8 0-.7.3-1.3.7-1.8-.4-.8-.5-1.7-.3-2.7v-.2c.1-.6.2-1.5.6-2.4.7-1.3 2-2 3.5-2H9c.5-.4 1.1-.7 1.8-.7 1.5 0 2.7 1.3 2.7 2.8v1.1c.5-.2 1.1-.3 1.7-.3.3 0 .5 0 .8.1.4-.5 1-.8 1.6-.9.1-.2.2-.3.3-.5.4-.6 1.1-1 1.8-1.1.6-.1 1.8-.2 3.2-.2 1.6 0 2.9.2 3.9.7.3-1.1 1.1-1.9 2.3-2.1l2.6-.4h.4c.8 0 1.5.3 2 .9.2.2.5.6.6.9l.1.3c.5-.3 1-.5 1.6-.5l3.9-.1c1.9 0 3.6-.1 3.6-.2h.2c.7 0 1.5.3 2 .8.4.4.7.9.8 1.5h.2c.3 0 .5 0 .8.1.4-.5 1-.8 1.6-.9.5-.7 1.4-1.3 2.4-1.3h2.6c.5-.6 1.2-1 2.1-1h3.2c1.5 0 2.7 1.2 2.8 2.7 0 1.1-.6 2.1-1.5 2.5v6.1c.8.4 1.4 1.3 1.5 2.3.1 1.5-1.1 2.8-2.6 2.9z" class="st1"/><path d="M32.3 8.5l-.7 3.6 2-.3z" class="st1"/><path d="M8.4 12c-.7-.1-1.1-.6-.9-2v-.2c.2-1.2.3-1.5.9-1.5.2 0 .4.1.6.3.2.2.6.5.8 1.1.2.4.2.7.3 1v.4c0 .2.2.4.5.5.3.1.6-.2.7-.5 0 0 .2-3.8.2-3.9 0-.3-.3-.6-.6-.6s-.6.3-.6.6v1.1c-.5-.5-1.1-1-1.8-1C6.6 7 6.4 8.7 6.3 9.7v.2c-.2 1.9.4 3.1 1.9 3.4 1.6.3 2.7.6 2.7 1.6 0 .4-.2.8-.6 1.1-.4.4-1 .5-1.6.4-.2 0-.3-.1-.5-.1-.2-.1-.8-.4-1-.8-.1-.4-.2-.9-.2-1.2v-.2c0-.3-.3-.6-.6-.6s-.6.3-.6.6c0 0 0 1.2-.1 1.9-.1 1.2 0 2.1 0 2.2 0 .3.3.6.6.6s.6-.3.6-.6v-1.1c.4.3 1 .6 1.7.7.9.2 1.8-.1 2.5-.7.6-.5 1-1.3 1-2 0-2.5-2.5-2.9-3.7-3.1M25.2 10.3c-.1.1-.2.2-.4.3-.1.1-.4.2-.5.2l-.3.1c-.4.2-1 .3-1.6.4V8.5c1.6 0 3 .1 3.3.6v.2c0 .2-.2.6-.5 1m3.5 5.4c-.3-.1-.7.1-.8.4-.2.7-.4.7-.5.8-.1.1-.3 0-.6-.1 0 0-.1-.2-.2-.3-.1-.2-.2-1-.2-1.5 0-1.8-.4-2.8-.9-3.3.3-.2.6-.5.6-.5.7-1 .9-1.8.5-2.5-1-1.7-5.3-1.2-6.7-1-.3 0-.6.4-.5.7 0 .3.4.6.7.5.3 0 .6-.1.9-.1v2.8h-.3c-.3 0-.6.3-.6.6s.3.6.6.6h.3v3.5l-.8.1c-.3 0-.6.4-.5.7 0 .3.4.6.7.5l2.9-.4c.3 0 .6-.4.5-.7 0-.3-.4-.6-.7-.5l-.9.1v-3.5c.6-.1 1.1-.2 1.6-.4h.2c.2 0 .4.1.5.3.2.3.4.9.5 2.4 0 .3.1 1.5.3 2 .1.2.4.7.9.9.4.1.9.3 1.5 0 .5-.3.9-.6 1.1-1.5.4-.2.2-.5-.1-.6M50.5 13.8c-.3 0-.6.3-.6.6v.8c0 .3-.1.7-.2.8-.1.2-.2.3-.4.5-.1.1-.3.2-.5.3-.2.1-.3.1-.7.1h-.4c-1.6.1-1.8-1.2-1.8-1.5v-2.6c.1-1 .3-1.7.7-2 .3-.2.7-.1 1.4.1.8.3 1.3 1.2 1.4 1.2.1.2.4.3.7.3.3-.1.4-.3.4-.6V9.1c0-.3-.3-.6-.6-.6s-.6.3-.6.6v1.1c-.2-.2-.5-.3-.8-.5-.3-.2-1.5-.7-2.4-.1-.7.5-1.2 1.4-1.3 2.9v2.8c.1.9.8 2.7 3 2.7h.3c.4 0 .8 0 1.2-.2.3-.1.6-.3.9-.6.2-.2.3-.4.5-.7.2-.4.3-1.1.4-1.3v-1c0-.2-.3-.4-.6-.4M60.4 17.8c0-.3-.3-.6-.6-.6-.2 0-.5 0-.8.1 0-1 0-3.1-.1-9.9h.9c.3 0 .6-.3.6-.6s-.3-.6-.6-.6l-3.2.1c-.3 0-.6.3-.6.6s.3.6.6.6h1v4.2l-3.6.6V8.5h1c.3 0 .6-.3.6-.6s-.3-.6-.6-.6h-3.2c-.3 0-.6.3-.6.6s.3.6.6.6h1v8.1h-1c-.3 0-.6.3-.6.6s.3.6.6.6l3.3.1c.3 0 .6-.3.6-.6s-.3-.6-.6-.6h-1v-3.1l3.6-.6v4.6c-.8.2-1.4.2-1.7.6-.2.2-.2.6.1.8.2.2.5.1.9 0 .3-.2 1.5-.3 2.9-.4.3-.2.5-.5.5-.8" class="st0"/><path d="M31.6 12.1l.7-3.6 1.3 3.3-2 .3zm5.3 1c-.2.1-.5.2-1.1.5l-.8-1.9-2.3-5.5c0-.1-.1-.3-.2-.3-.1-.1-.3-.2-.5-.2l-2.6.3c-.3 0-.6.3-.5.7 0 .3.3.6.7.5 0 0 1-.1 1.8-.2-.2 1.1-1.1 5.6-1.4 7l-1.8-.1c-.3 0-.6.2-.6.6 0 .3.2.6.6.6l3 .1c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6l.1-.9 2.8-.5.6 1.5c-.5.3-.7.4-1 .7-.2.3-.1.6.1.8.3.2.7.1.9-.1.3-.4 1.4-.9 2.5-1.3.3-.1.5-.5.4-.8-.1-.2-.4-.4-.7-.3" class="st0"/><path d="M44.1 7s-1.8.1-3.8.2l-3.9.1c-.2 0-.3.1-.5.2-.1.1-.2.3-.1.5l.5 3c0 .3.4.6.7.5.3 0 .5-.3.5-.6 0 0-.2-1.6-.4-2.4h2.6v7.9h-1.3c-.3 0-.6.3-.6.6s.3.6.6.6l3.7-.1c.3 0 .6-.3.6-.6s-.3-.6-.6-.6h-1.2V8.4c1 0 1.9-.1 2.5-.1v1.2c0 .6.1.8.1.9.2.3.5.4.8.2.2-.1.3-.4.3-.6 0 0 0-1.4.1-2.2 0-.2 0-.3-.2-.5 0-.2-.2-.3-.4-.3M18.6 14.4c-.3 0-.6.3-.6.6V15.9c0 .2-.1.6-.2.8-.1.2-.2.3-.4.5-.1.1-.3.2-.5.3-.2.1-.3.1-.7.1h-.4c-1.6 0-1.8-1.2-1.8-1.5v-2.6c.1-1 .3-1.7.7-2 .3-.2.7-.1 1.4.1.8.3 1.4 1.2 1.4 1.2.1.2.4.3.7.3.3-.1.4-.3.4-.6V9.8c0-.3-.3-.6-.6-.6s-.6.3-.6.6v1.1c-.2-.2-.5-.4-.8-.5-.4-.2-1.5-.6-2.5-.1-.7.5-1.2 1.4-1.3 2.9V16c.1.9.8 2.7 3.1 2.7h.3c.4 0 .8 0 1.2-.2.3-.1.6-.3.9-.6.2-.2.3-.4.5-.7.2-.4.3-1.1.4-1.3v-1c0-.2-.3-.5-.6-.5" class="st0"/></g></g></switch>
-<g transform="translate(68,0)">
-<path fill="white" d="M9.984 20.016h-4.969v-8.016h-3l9.984-9 9.984 9h-3v8.016h-4.969v-6h-4.031v6z"></path>
-</g>
-</svg>
+<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" viewBox="0 0 66.1 24.7"><style>.st0{fill:#fff}.st1{fill:#f9a83a}</style><switch><g><g><g><path d="M60.2 24.1c-.8.1-1.3.1-1.5.2-.4.2-1.3.4-2.4.4-1.4 0-2.7-.5-3.8-1.3h-.8c-.3 0-.5 0-.8-.1-1.1.4-2.1.4-2.7.4H48c-1.4.1-2.8-.2-4-.8-.6.2-1.1.3-1.7.3l-3.7.1c-1.7 0-3.2-.6-4.4-1.7-.5 0-1-.1-1.4-.2-.6.7-1.4 1.3-2.4 1.8-1.9.9-4 1-6 .2-.2-.1-.5-.2-.7-.3l-2.3.3h-.7c-.3.1-.5.3-.7.4-1.5.7-2.9.7-3.5.7H16c-1.7 0-3.4-.5-4.7-1.4-.4.1-.9.2-1.3.2-.9.6-2 1-3.2 1.1h-.4c-3.3 0-6-2.5-6.3-5.8v-.1c0-.5-.1-1.6 0-2.8 0-.6.1-1.5.1-1.7 0-.8.2-1.6.5-2.4-.2-.8-.1-1.6 0-2.4v-.3c.1-.7.3-2.1 1-3.5C3 3 5.4 1.5 8.1 1.5 9 1 9.9.8 10.9.8h.3c2 .1 3.8 1.1 4.9 2.7.9-.8 2-1.3 3.2-1.5 2.4-.3 4.4-.4 6.1-.1.9-.8 2.1-1.4 3.3-1.5l2.6-.4h.8c1.5 0 3 .6 4.2 1.6h.2l3.8-.1c1.6 0 3-.1 3.3-.1h.5c1.4 0 2.9.5 4 1.4 1.1-.8 2.4-1.2 3.8-1.2h1.3c1-.6 2.1-1 3.3-1l3.2-.1h.1c3.4 0 6.2 2.8 6.3 6.2 0 1.6-.5 3-1.5 4.2v2.9c.9 1 1.4 2.3 1.5 3.7.2 3.4-2.4 6.3-5.9 6.6z" class="st0"/></g><path d="M60 20.5c-1.3.1-2.1.2-2.3.3l-.1.1c-.3.1-.7.3-1.2.3-.6 0-1.3-.2-1.8-.7-.2-.2-.4-.4-.5-.6h-2.3c-.4 0-.8-.1-1.1-.3-.1.1-.3.1-.4.2-.8.4-1.5.4-2 .4h-.5c-1.5 0-2.7-.5-3.5-1.4-.5.5-1.2.8-1.9.8l-3.7.1c-1.3 0-2.5-1-2.7-2.2-.5.3-1 .5-1.6.5-.6 0-1.2-.2-1.7-.5-.1-.1-.2-.2-.3-.2-.3.2-.7.2-1.1.2H31c-.4 1.2-1.1 2-2.2 2.5-.5.2-1.1.4-1.6.4s-1.1-.1-1.6-.3c-.5-.2-.9-.5-1.2-.8-.2.1-.4.1-.6.2l-2.9.4h-.4c-.3 0-.5 0-.8-.1-.4.4-.9.6-1.3.8-.8.4-1.5.4-2 .4h-.5c-1.8 0-3.2-.8-4-1.9-.8.5-1.8.8-2.7.8h-.6c0 .1-.1.1-.1.2-.5.5-1.2.9-1.9.9h-.2c-1.4 0-2.6-1.1-2.7-2.6v-.1c0-.5-.1-1.4 0-2.4 0-.7.1-1.8.1-1.8 0-.7.3-1.3.7-1.8-.4-.8-.5-1.7-.3-2.7v-.2c.1-.6.2-1.5.6-2.4.7-1.3 2-2 3.5-2H9c.5-.4 1.1-.7 1.8-.7 1.5 0 2.7 1.3 2.7 2.8v1.1c.5-.2 1.1-.3 1.7-.3.3 0 .5 0 .8.1.4-.5 1-.8 1.6-.9.1-.2.2-.3.3-.5.4-.6 1.1-1 1.8-1.1.6-.1 1.8-.2 3.2-.2 1.6 0 2.9.2 3.9.7.3-1.1 1.1-1.9 2.3-2.1l2.6-.4h.4c.8 0 1.5.3 2 .9.2.2.5.6.6.9l.1.3c.5-.3 1-.5 1.6-.5l3.9-.1c1.9 0 3.6-.1 3.6-.2h.2c.7 0 1.5.3 2 .8.4.4.7.9.8 1.5h.2c.3 0 .5 0 .8.1.4-.5 1-.8 1.6-.9.5-.7 1.4-1.3 2.4-1.3h2.6c.5-.6 1.2-1 2.1-1h3.2c1.5 0 2.7 1.2 2.8 2.7 0 1.1-.6 2.1-1.5 2.5v6.1c.8.4 1.4 1.3 1.5 2.3.1 1.5-1.1 2.8-2.6 2.9z" class="st1"/><path d="M32.3 8.5l-.7 3.6 2-.3z" class="st1"/><path d="M8.4 12c-.7-.1-1.1-.6-.9-2v-.2c.2-1.2.3-1.5.9-1.5.2 0 .4.1.6.3.2.2.6.5.8 1.1.2.4.2.7.3 1v.4c0 .2.2.4.5.5.3.1.6-.2.7-.5 0 0 .2-3.8.2-3.9 0-.3-.3-.6-.6-.6s-.6.3-.6.6v1.1c-.5-.5-1.1-1-1.8-1C6.6 7 6.4 8.7 6.3 9.7v.2c-.2 1.9.4 3.1 1.9 3.4 1.6.3 2.7.6 2.7 1.6 0 .4-.2.8-.6 1.1-.4.4-1 .5-1.6.4-.2 0-.3-.1-.5-.1-.2-.1-.8-.4-1-.8-.1-.4-.2-.9-.2-1.2v-.2c0-.3-.3-.6-.6-.6s-.6.3-.6.6c0 0 0 1.2-.1 1.9-.1 1.2 0 2.1 0 2.2 0 .3.3.6.6.6s.6-.3.6-.6v-1.1c.4.3 1 .6 1.7.7.9.2 1.8-.1 2.5-.7.6-.5 1-1.3 1-2 0-2.5-2.5-2.9-3.7-3.1M25.2 10.3c-.1.1-.2.2-.4.3-.1.1-.4.2-.5.2l-.3.1c-.4.2-1 .3-1.6.4V8.5c1.6 0 3 .1 3.3.6v.2c0 .2-.2.6-.5 1m3.5 5.4c-.3-.1-.7.1-.8.4-.2.7-.4.7-.5.8-.1.1-.3 0-.6-.1 0 0-.1-.2-.2-.3-.1-.2-.2-1-.2-1.5 0-1.8-.4-2.8-.9-3.3.3-.2.6-.5.6-.5.7-1 .9-1.8.5-2.5-1-1.7-5.3-1.2-6.7-1-.3 0-.6.4-.5.7 0 .3.4.6.7.5.3 0 .6-.1.9-.1v2.8h-.3c-.3 0-.6.3-.6.6s.3.6.6.6h.3v3.5l-.8.1c-.3 0-.6.4-.5.7 0 .3.4.6.7.5l2.9-.4c.3 0 .6-.4.5-.7 0-.3-.4-.6-.7-.5l-.9.1v-3.5c.6-.1 1.1-.2 1.6-.4h.2c.2 0 .4.1.5.3.2.3.4.9.5 2.4 0 .3.1 1.5.3 2 .1.2.4.7.9.9.4.1.9.3 1.5 0 .5-.3.9-.6 1.1-1.5.4-.2.2-.5-.1-.6M50.5 13.8c-.3 0-.6.3-.6.6v.8c0 .3-.1.7-.2.8-.1.2-.2.3-.4.5-.1.1-.3.2-.5.3-.2.1-.3.1-.7.1h-.4c-1.6.1-1.8-1.2-1.8-1.5v-2.6c.1-1 .3-1.7.7-2 .3-.2.7-.1 1.4.1.8.3 1.3 1.2 1.4 1.2.1.2.4.3.7.3.3-.1.4-.3.4-.6V9.1c0-.3-.3-.6-.6-.6s-.6.3-.6.6v1.1c-.2-.2-.5-.3-.8-.5-.3-.2-1.5-.7-2.4-.1-.7.5-1.2 1.4-1.3 2.9v2.8c.1.9.8 2.7 3 2.7h.3c.4 0 .8 0 1.2-.2.3-.1.6-.3.9-.6.2-.2.3-.4.5-.7.2-.4.3-1.1.4-1.3v-1c0-.2-.3-.4-.6-.4M60.4 17.8c0-.3-.3-.6-.6-.6-.2 0-.5 0-.8.1 0-1 0-3.1-.1-9.9h.9c.3 0 .6-.3.6-.6s-.3-.6-.6-.6l-3.2.1c-.3 0-.6.3-.6.6s.3.6.6.6h1v4.2l-3.6.6V8.5h1c.3 0 .6-.3.6-.6s-.3-.6-.6-.6h-3.2c-.3 0-.6.3-.6.6s.3.6.6.6h1v8.1h-1c-.3 0-.6.3-.6.6s.3.6.6.6l3.3.1c.3 0 .6-.3.6-.6s-.3-.6-.6-.6h-1v-3.1l3.6-.6v4.6c-.8.2-1.4.2-1.7.6-.2.2-.2.6.1.8.2.2.5.1.9 0 .3-.2 1.5-.3 2.9-.4.3-.2.5-.5.5-.8" class="st0"/><path d="M31.6 12.1l.7-3.6 1.3 3.3-2 .3zm5.3 1c-.2.1-.5.2-1.1.5l-.8-1.9-2.3-5.5c0-.1-.1-.3-.2-.3-.1-.1-.3-.2-.5-.2l-2.6.3c-.3 0-.6.3-.5.7 0 .3.3.6.7.5 0 0 1-.1 1.8-.2-.2 1.1-1.1 5.6-1.4 7l-1.8-.1c-.3 0-.6.2-.6.6 0 .3.2.6.6.6l3 .1c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6l.1-.9 2.8-.5.6 1.5c-.5.3-.7.4-1 .7-.2.3-.1.6.1.8.3.2.7.1.9-.1.3-.4 1.4-.9 2.5-1.3.3-.1.5-.5.4-.8-.1-.2-.4-.4-.7-.3" class="st0"/><path d="M44.1 7s-1.8.1-3.8.2l-3.9.1c-.2 0-.3.1-.5.2-.1.1-.2.3-.1.5l.5 3c0 .3.4.6.7.5.3 0 .5-.3.5-.6 0 0-.2-1.6-.4-2.4h2.6v7.9h-1.3c-.3 0-.6.3-.6.6s.3.6.6.6l3.7-.1c.3 0 .6-.3.6-.6s-.3-.6-.6-.6h-1.2V8.4c1 0 1.9-.1 2.5-.1v1.2c0 .6.1.8.1.9.2.3.5.4.8.2.2-.1.3-.4.3-.6 0 0 0-1.4.1-2.2 0-.2 0-.3-.2-.5 0-.2-.2-.3-.4-.3M18.6 14.4c-.3 0-.6.3-.6.6V15.9c0 .2-.1.6-.2.8-.1.2-.2.3-.4.5-.1.1-.3.2-.5.3-.2.1-.3.1-.7.1h-.4c-1.6 0-1.8-1.2-1.8-1.5v-2.6c.1-1 .3-1.7.7-2 .3-.2.7-.1 1.4.1.8.3 1.4 1.2 1.4 1.2.1.2.4.3.7.3.3-.1.4-.3.4-.6V9.8c0-.3-.3-.6-.6-.6s-.6.3-.6.6v1.1c-.2-.2-.5-.4-.8-.5-.4-.2-1.5-.6-2.5-.1-.7.5-1.2 1.4-1.3 2.9V16c.1.9.8 2.7 3.1 2.7h.3c.4 0 .8 0 1.2-.2.3-.1.6-.3.9-.6.2-.2.3-.4.5-.7.2-.4.3-1.1.4-1.3v-1c0-.2-.3-.5-.6-.5" class="st0"/></g></g></switch></svg>
diff --git a/packages/scratch-gui/src/components/modal/modal.jsx b/packages/scratch-gui/src/components/modal/modal.jsx
index 32fe050285..bbea85b337 100644
--- a/packages/scratch-gui/src/components/modal/modal.jsx
+++ b/packages/scratch-gui/src/components/modal/modal.jsx
@@ -17,7 +17,9 @@ const ModalComponent = props => (
     <ReactModal
         isOpen
         className={classNames(styles.modalContent, props.className, {
-            [styles.fullScreen]: props.fullScreen
+            [styles.fullScreen]: props.fullScreen,
+            // Used by scratch-platorm to distinguish between editor modals and other modals
+            'scratch-editor-modal': true
         })}
         contentLabel={props.contentLabel}
         overlayClassName={styles.modalOverlay}
diff --git a/packages/scratch-gui/src/components/scratch-image/scratch-image.jsx b/packages/scratch-gui/src/components/scratch-image/scratch-image.jsx
index a612eb6c6a..6ac67c6d6d 100644
--- a/packages/scratch-gui/src/components/scratch-image/scratch-image.jsx
+++ b/packages/scratch-gui/src/components/scratch-image/scratch-image.jsx
@@ -3,7 +3,6 @@ import React from 'react';
 import VisibilitySensor from 'react-visibility-sensor';
 
 import {legacyConfig} from '../../legacy-config';
-import {PLATFORM} from '../../lib/platform';
 
 class ScratchImage extends React.PureComponent {
     static init () {
@@ -25,7 +24,8 @@ class ScratchImage extends React.PureComponent {
                 nextImage = image;
                 break;
             } else {
-                // nextImage = nextImage || image;
+                // TODO: Why was this commented out on native branch?
+                nextImage = nextImage || image;
             }
         }
 
@@ -56,7 +56,7 @@ class ScratchImage extends React.PureComponent {
     constructor (props) {
         super(props);
         this.state = {};
-        Object.assign(this.state, this._loadImageSource(props.imageSource, props.platform));
+        Object.assign(this.state, this._loadImageSource(props.imageSource));
     }
     componentWillReceiveProps (nextProps) {
         const newState = this._loadImageSource(nextProps.imageSource);
@@ -95,6 +95,7 @@ class ScratchImage extends React.PureComponent {
     }
     render () {
         const {
+            // TODO: Does this cause issues for desktop?
             src: _src, // eslint-disable-line react/prop-types
             imageSource: _imageSource,
 
@@ -111,7 +112,7 @@ class ScratchImage extends React.PureComponent {
                         ScratchImage.loadPendingImages();
                         return (
                             <img
-                                src={this.props.platform === PLATFORM.ANDROID ? `file:///android_asset/www${this.state.imageURI}` : this.state.imageURI}
+                                src={this.state.imageURI}
                                 style={{
                                     minWidth: '1px',
                                     minHeight: '1px'
@@ -129,7 +130,11 @@ class ScratchImage extends React.PureComponent {
 ScratchImage.ImageSourcePropType = PropTypes.oneOfType([
     PropTypes.shape({
         assetId: PropTypes.string.isRequired,
-        assetType: PropTypes.oneOf(Object.values(legacyConfig.storage.scratchStorage.AssetType)).isRequired
+        assetType: PropTypes.oneOf(
+            Object.values(
+                legacyConfig.storage.scratchStorage.AssetType
+            )
+        ).isRequired
     }),
     PropTypes.shape({
         uri: PropTypes.string.isRequired
@@ -137,8 +142,7 @@ ScratchImage.ImageSourcePropType = PropTypes.oneOfType([
 ]);
 
 ScratchImage.propTypes = {
-    imageSource: ScratchImage.ImageSourcePropType.isRequired,
-    platform: PropTypes.string
+    imageSource: ScratchImage.ImageSourcePropType.isRequired
 };
 
 ScratchImage.init();
diff --git a/packages/scratch-gui/src/containers/cards.jsx b/packages/scratch-gui/src/containers/cards.jsx
index 3a22967cf4..b2623faa79 100644
--- a/packages/scratch-gui/src/containers/cards.jsx
+++ b/packages/scratch-gui/src/containers/cards.jsx
@@ -19,6 +19,7 @@ import {
 
 import CardsComponent from '../components/cards/cards.jsx';
 import {loadImageData} from '../lib/libraries/decks/translate-image.js';
+import {PLATFORM} from '../lib/platform.js';
 
 class Cards extends React.Component {
     componentDidMount () {
@@ -32,15 +33,22 @@ class Cards extends React.Component {
         }
     }
     render () {
+        const props = {
+            ...this.props,
+            // Assume user is offline and don't attempt to
+            // download and show videos
+            showVideos: this.props.platform !== PLATFORM.DESKTOP &&
+                this.props.platform !== PLATFORM.ANDROID
+        };
         return (
-            <CardsComponent {...this.props} />
+            <CardsComponent {...props} />
         );
     }
 }
 
 Cards.propTypes = {
     locale: PropTypes.string.isRequired,
-    platform: PropTypes.string
+    platform: PropTypes.oneOf(Object.keys(PLATFORM))
 };
 
 const mapStateToProps = state => ({
diff --git a/packages/scratch-gui/src/containers/gui.jsx b/packages/scratch-gui/src/containers/gui.jsx
index 5ff6d12266..c78fafc640 100644
--- a/packages/scratch-gui/src/containers/gui.jsx
+++ b/packages/scratch-gui/src/containers/gui.jsx
@@ -39,15 +39,14 @@ import vmListenerHOC from '../lib/vm-listener-hoc.jsx';
 import vmManagerHOC from '../lib/vm-manager-hoc.jsx';
 import cloudManagerHOC from '../lib/cloud-manager-hoc.jsx';
 import systemPreferencesHOC from '../lib/system-preferences-hoc.jsx';
+import {PLATFORM} from '../lib/platform.js';
 
 import GUIComponent from '../components/gui/gui.jsx';
-import {setIsScratchDesktop} from '../lib/isScratchDesktop.js';
 import {GUIStoragePropType} from '../gui-config';
 import {AccountMenuOptionsPropTypes} from '../lib/account-menu-options';
 
 class GUI extends React.Component {
     componentDidMount () {
-        setIsScratchDesktop(this.props.isScratchDesktop);
         this.props.onStorageInit(this.props.storage.scratchStorage);
         this.props.onVmInit(this.props.vm);
         this.props.storage.setProjectMetadata?.(this.props.projectId);
@@ -83,7 +82,6 @@ class GUI extends React.Component {
             cloudHost,
             error,
             isError,
-            isScratchDesktop,
             isShowingProject,
             onProjectLoaded,
             onStorageInit,
@@ -122,7 +120,6 @@ GUI.propTypes = {
     intl: intlShape,
     isError: PropTypes.bool,
     isLoading: PropTypes.bool,
-    isScratchDesktop: PropTypes.bool,
     isShowingProject: PropTypes.bool,
     isTotallyNormal: PropTypes.bool,
     loadingStateVisible: PropTypes.bool,
@@ -131,7 +128,7 @@ GUI.propTypes = {
     onStorageInit: PropTypes.func,
     onUpdateProjectId: PropTypes.func,
     onVmInit: PropTypes.func,
-    platform: PropTypes.string,
+    platform: PropTypes.oneOf(Object.keys(PLATFORM)),
     setPlatform: PropTypes.func.isRequired,
     projectHost: PropTypes.string,
     projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
@@ -139,12 +136,12 @@ GUI.propTypes = {
     telemetryModalVisible: PropTypes.bool,
     username: PropTypes.string,
     userOwnsProject: PropTypes.bool,
+    // TODO: Is this unused?
     hideTutorialProjects: PropTypes.bool,
     vm: PropTypes.instanceOf(VM).isRequired
 };
 
 GUI.defaultProps = {
-    isScratchDesktop: false,
     isTotallyNormal: false,
     onStorageInit: () => {},
     onProjectLoaded: () => {},
diff --git a/packages/scratch-gui/src/containers/library-item.jsx b/packages/scratch-gui/src/containers/library-item.jsx
index c130618b45..b0e0e07ca0 100644
--- a/packages/scratch-gui/src/containers/library-item.jsx
+++ b/packages/scratch-gui/src/containers/library-item.jsx
@@ -2,7 +2,6 @@ import bindAll from 'lodash.bindall';
 import PropTypes from 'prop-types';
 import React from 'react';
 import {injectIntl} from 'react-intl';
-import {connect} from 'react-redux';
 
 import LibraryItemComponent from '../components/library-item/library-item.jsx';
 
@@ -22,6 +21,7 @@ class LibraryItem extends React.PureComponent {
             'startRotatingIcons',
             'stopRotatingIcons'
         ]);
+        this.hasIconsArray = Array.isArray(props.icons);
         this.state = {
             iconIndex: 0,
             isRotatingIcon: false
@@ -53,7 +53,7 @@ class LibraryItem extends React.PureComponent {
     handleMouseEnter () {
         if (!this.props.showPlayButton) {
             this.props.onMouseEnter(this.props.id);
-            if (this.props.icons && this.props.icons.length) {
+            if (this.hasIconsArray) {
                 this.stopRotatingIcons();
                 this.setState({
                     isRotatingIcon: true
@@ -64,7 +64,7 @@ class LibraryItem extends React.PureComponent {
     handleMouseLeave () {
         if (!this.props.showPlayButton) {
             this.props.onMouseLeave(this.props.id);
-            if (this.props.icons && this.props.icons.length) {
+            if (this.hasIconsArray) {
                 this.setState({
                     isRotatingIcon: false
                 }, this.stopRotatingIcons);
@@ -91,13 +91,18 @@ class LibraryItem extends React.PureComponent {
         this.setState({iconIndex: nextIconIndex});
     }
     curIconSource () {
-        if (this.props.icons &&
-            this.state.isRotatingIcon &&
-            this.state.iconIndex < this.props.icons.length &&
-            this.props.icons[this.state.iconIndex]) {
-            return this.props.icons[this.state.iconIndex];
+        if (this.hasIconsArray) {
+            if (this.state.isRotatingIcon &&
+                this.state.iconIndex < this.props.icons.length &&
+                this.props.icons[this.state.iconIndex]) {
+                // multiple icons, currently animating: show current frame
+                return this.props.icons[this.state.iconIndex];
+            }
+            // multiple icons, not currently animating: show first frame
+            return this.props.icons[0];
         }
-        return this.props.iconSource;
+        // single icon
+        return this.props.icons;
     }
     render () {
         const iconSource = this.curIconSource();
@@ -116,7 +121,6 @@ class LibraryItem extends React.PureComponent {
                 internetConnectionRequired={this.props.internetConnectionRequired}
                 isPlaying={this.props.isPlaying}
                 name={this.props.name}
-                platform={this.props.platform}
                 showPlayButton={this.props.showPlayButton}
                 onBlur={this.handleBlur}
                 onClick={this.handleClick}
@@ -131,10 +135,6 @@ class LibraryItem extends React.PureComponent {
     }
 }
 
-const mapStateToProps = state => ({
-    platform: state.scratchGui.platform.platform
-});
-
 LibraryItem.propTypes = {
     bluetoothRequired: PropTypes.bool,
     collaborator: PropTypes.string,
@@ -146,9 +146,11 @@ LibraryItem.propTypes = {
     extensionId: PropTypes.string,
     featured: PropTypes.bool,
     hidden: PropTypes.bool,
-    iconSource: LibraryItemComponent.propTypes.iconSource, // single icon
-    icons: PropTypes.arrayOf(LibraryItemComponent.propTypes.iconSource), // rotating icons
-    id: PropTypes.number.isRequired,
+    icons: PropTypes.oneOfType([
+        LibraryItemComponent.propTypes.iconSource, // single icon
+        PropTypes.arrayOf(LibraryItemComponent.propTypes.iconSource) // rotating icons
+    ]),
+    id: PropTypes.string.isRequired,
     insetIconURL: PropTypes.string,
     internetConnectionRequired: PropTypes.bool,
     isPlaying: PropTypes.bool,
@@ -159,8 +161,7 @@ LibraryItem.propTypes = {
     onMouseEnter: PropTypes.func.isRequired,
     onMouseLeave: PropTypes.func.isRequired,
     onSelect: PropTypes.func.isRequired,
-    platform: PropTypes.string,
     showPlayButton: PropTypes.bool
 };
 
-export default connect(mapStateToProps)(injectIntl(LibraryItem));
+export default injectIntl(LibraryItem);
diff --git a/packages/scratch-gui/src/containers/tips-library.jsx b/packages/scratch-gui/src/containers/tips-library.jsx
index bbacebb6b7..3f9a1d8556 100644
--- a/packages/scratch-gui/src/containers/tips-library.jsx
+++ b/packages/scratch-gui/src/containers/tips-library.jsx
@@ -7,7 +7,7 @@ import decksLibraryContent from '../lib/libraries/decks/index.jsx';
 import tutorialTags from '../lib/libraries/tutorial-tags';
 
 import analytics from '../lib/analytics';
-import {isScratchDesktop} from '../lib/isScratchDesktop';
+import {PLATFORM} from '../lib/platform.js';
 
 import LibraryComponent from '../components/library/library.jsx';
 
@@ -58,6 +58,9 @@ class TipsLibrary extends React.PureComponent {
             return window.open(window.location.origin + urlParams, '_blank');
         }
 
+        if (this.props.onTutorialSelect) {
+            this.props.onTutorialSelect();
+        }
         this.props.onActivateDeck(item.id);
     }
     render () {
@@ -73,11 +76,16 @@ class TipsLibrary extends React.PureComponent {
                 const isProjectTutorial = Object.prototype.hasOwnProperty.call(deck, 'requiredProjectId');
                 const isVideoOnlyTutorial = decksLibraryContent[id].steps.filter(s => s.title).length === 0;
 
-                if (isProjectTutorial && (this.props.hideTutorialProjects || isScratchDesktop())) {
+                if (isProjectTutorial &&
+                    (this.props.hideTutorialProjects ||
+                        this.props.platform === PLATFORM.DESKTOP ||
+                        this.props.platform === PLATFORM.ANDROID)
+                ) {
                     return false;
                 }
 
-                if (isVideoOnlyTutorial && isScratchDesktop()) {
+                if (isVideoOnlyTutorial &&
+                    (this.props.platform === PLATFORM.DESKTOP || this.props.platform === PLATFORM.ANDROID)) {
                     return false;
                 }
 
@@ -113,17 +121,20 @@ class TipsLibrary extends React.PureComponent {
 }
 
 TipsLibrary.propTypes = {
+    onTutorialSelect: PropTypes.func,
     intl: intlShape.isRequired,
     onActivateDeck: PropTypes.func.isRequired,
     onRequestClose: PropTypes.func,
     projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+    platform: PropTypes.oneOf(Object.keys(PLATFORM)),
     visible: PropTypes.bool,
     hideTutorialProjects: PropTypes.bool
 };
 
 const mapStateToProps = state => ({
     visible: state.scratchGui.modals.tipsLibrary,
-    projectId: state.scratchGui.projectState.projectId
+    projectId: state.scratchGui.projectState.projectId,
+    platform: state.scratchGui.platform.platform
 });
 
 const mapDispatchToProps = dispatch => ({
diff --git a/packages/scratch-gui/src/exported-reducers.ts b/packages/scratch-gui/src/exported-reducers.ts
index c580fe8a12..219ce63a36 100644
--- a/packages/scratch-gui/src/exported-reducers.ts
+++ b/packages/scratch-gui/src/exported-reducers.ts
@@ -3,7 +3,21 @@ import LocalesReducer, {localesInitialState, initLocale} from './reducers/locale
 import GuiReducer, {buildInitialState, guiMiddleware, initEmbedded, initFullScreen, initPlayer} from './reducers/gui';
 import {setFullScreen, setPlayer} from './reducers/mode.js';
 import {activateDeck} from './reducers/cards.js';
-import {remixProject} from './reducers/project-state.js';
+import {
+    LoadingStates,
+    onFetchedProjectData,
+    onLoadedProject,
+    defaultProjectId,
+    remixProject,
+    requestNewProject,
+    requestProjectUpload,
+    setProjectId
+} from './reducers/project-state.js';
+import {
+    openLoadingProject,
+    closeLoadingProject,
+    openTelemetryModal
+} from './reducers/modals.js';
 
 export const guiReducers = {
     locales: LocalesReducer,
@@ -12,6 +26,19 @@ export const guiReducers = {
 };
 
 export {
+    LoadingStates,
+    onFetchedProjectData,
+    onLoadedProject,
+    defaultProjectId,
+    remixProject,
+    requestNewProject,
+    requestProjectUpload,
+    setProjectId,
+
+    openLoadingProject,
+    closeLoadingProject,
+    openTelemetryModal,
+    
     buildInitialState,
     guiMiddleware,
     initEmbedded,
@@ -21,6 +48,5 @@ export {
     localesInitialState,
     setFullScreen,
     setPlayer,
-    activateDeck,
-    remixProject
+    activateDeck
 };
diff --git a/packages/scratch-gui/src/index.ts b/packages/scratch-gui/src/index.ts
index f7652e7400..47a926acda 100644
--- a/packages/scratch-gui/src/index.ts
+++ b/packages/scratch-gui/src/index.ts
@@ -2,6 +2,7 @@ import {buildInitialState} from './reducers/gui';
 import {legacyConfig} from './legacy-config';
 
 export {default} from './containers/gui.jsx';
+export {default as GUIComponent} from './components/gui/gui.jsx';
 export {default as AppStateHOC} from './lib/app-state-hoc.jsx';
 export {remixProject} from './reducers/project-state.js';
 export {setAppElement} from 'react-modal';
diff --git a/packages/scratch-gui/src/lib/default-project/messages.js b/packages/scratch-gui/src/lib/default-project/messages.js
new file mode 100644
index 0000000000..fa0bfc1b9c
--- /dev/null
+++ b/packages/scratch-gui/src/lib/default-project/messages.js
@@ -0,0 +1,16 @@
+import {defineMessages} from 'react-intl';
+
+const messages = defineMessages({
+    meow: {
+        defaultMessage: 'Meow',
+        description: 'Name for the meow sound',
+        id: 'gui.defaultProject.meow'
+    },
+    variable: {
+        defaultMessage: 'my variable',
+        description: 'Name for the default variable',
+        id: 'gui.defaultProject.variable'
+    }
+});
+
+export default messages;
diff --git a/packages/scratch-gui/src/lib/default-project/project-data.ts b/packages/scratch-gui/src/lib/default-project/project-data.ts
index 40ff244376..c2d32aee74 100644
--- a/packages/scratch-gui/src/lib/default-project/project-data.ts
+++ b/packages/scratch-gui/src/lib/default-project/project-data.ts
@@ -1,21 +1,8 @@
-import {defineMessages} from 'react-intl';
+import projectDataMessages from './messages';
 import sharedMessages from '../shared-messages';
 import {MessageObject, TranslatorFunction} from '../../gui-config';
 
-let messages = defineMessages({
-    meow: {
-        defaultMessage: 'Meow',
-        description: 'Name for the meow sound',
-        id: 'gui.defaultProject.meow'
-    },
-    variable: {
-        defaultMessage: 'my variable',
-        description: 'Name for the default variable',
-        id: 'gui.defaultProject.variable'
-    }
-});
-
-messages = {...messages, ...sharedMessages};
+const messages = {...projectDataMessages, ...sharedMessages};
 
 // use the default message if a translation function is not passed
 const defaultTranslator = (msgObj: MessageObject) => msgObj.defaultMessage;
diff --git a/packages/scratch-gui/src/lib/isScratchDesktop.js b/packages/scratch-gui/src/lib/isScratchDesktop.js
deleted file mode 100644
index e159e38526..0000000000
--- a/packages/scratch-gui/src/lib/isScratchDesktop.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Internal stored state. Not valid until after at least one call to `setIsScratchDesktop()`.
- * @type {boolean}
- */
-let _isScratchDesktop; // undefined = not ready yet
-
-/**
- * Tell the `isScratchDesktop()` whether or not the GUI is running under Scratch Desktop.
- * @param {boolean} value - the new value which `isScratchDesktop()` should return in the future.
- */
-const setIsScratchDesktop = function (value) {
-    _isScratchDesktop = value;
-};
-
-/**
- * @returns {boolean} - true if it seems like the GUI is running under Scratch Desktop; false otherwise.
- * If `setIsScratchDesktop()` has not yet been called, this can return `undefined`.
- */
-const isScratchDesktop = function () {
-    return _isScratchDesktop;
-};
-
-/**
- * @returns {boolean} - false if it seems like the GUI is running under Scratch Desktop; true otherwise.
- */
-const notScratchDesktop = function () {
-    return !isScratchDesktop();
-};
-
-export default isScratchDesktop;
-export {
-    isScratchDesktop,
-    notScratchDesktop,
-    setIsScratchDesktop
-};
diff --git a/packages/scratch-gui/src/lib/project-saver-hoc.jsx b/packages/scratch-gui/src/lib/project-saver-hoc.jsx
index 2152a85a2c..2a7ed2c0e8 100644
--- a/packages/scratch-gui/src/lib/project-saver-hoc.jsx
+++ b/packages/scratch-gui/src/lib/project-saver-hoc.jsx
@@ -351,6 +351,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
                 reduxProjectId,
                 reduxProjectTitle,
                 setAutoSaveTimeoutId: setAutoSaveTimeoutIdProp,
+                saveThumbnailOnLoad,
                 /* eslint-enable no-unused-vars */
                 ...componentProps
             } = this.props;
@@ -400,7 +401,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
         onUpdateProjectData: PropTypes.func,
         onUpdateProjectThumbnail: PropTypes.func,
         onUpdatedProject: PropTypes.func,
-        noBeforeUnloadHandler: PropTypes.bool.required,
+        noBeforeUnloadHandler: PropTypes.bool.isRequired,
         projectChanged: PropTypes.bool,
         reduxProjectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
         reduxProjectTitle: PropTypes.string,
diff --git a/packages/scratch-gui/src/playground/render-gui-standalone.jsx b/packages/scratch-gui/src/playground/render-gui-standalone.jsx
index b07fcfb469..4da39edc8f 100644
--- a/packages/scratch-gui/src/playground/render-gui-standalone.jsx
+++ b/packages/scratch-gui/src/playground/render-gui-standalone.jsx
@@ -1,5 +1,6 @@
 import {EditorState, createStandaloneRoot, setAppElement} from '../index-standalone';
 import HashParserHOC from '../lib/hash-parser-hoc.jsx';
+import {PLATFORM} from '../lib/platform.js';
 
 import log from '../lib/log.js';
 
@@ -60,7 +61,7 @@ export default appTarget => {
     if (simulateScratchDesktop) {
         gui.render({
             canEditTitle: true,
-            isScratchDesktop: true,
+            platform: PLATFORM.DESKTOP,
             showTelemetryModal: true,
             canSave: false,
             onTelemetryModalCancel: handleTelemetryModalCancel,
diff --git a/packages/scratch-gui/src/playground/render-gui.jsx b/packages/scratch-gui/src/playground/render-gui.jsx
index 0f15fbfa70..04b12dd7c4 100644
--- a/packages/scratch-gui/src/playground/render-gui.jsx
+++ b/packages/scratch-gui/src/playground/render-gui.jsx
@@ -6,6 +6,7 @@ import AppStateHOC from '../lib/app-state-hoc.jsx';
 import GUI from '../containers/gui.jsx';
 import HashParserHOC from '../lib/hash-parser-hoc.jsx';
 import log from '../lib/log.js';
+import {PLATFORM} from '../lib/platform.js';
 
 const onClickLogo = () => {
     window.location = 'https://scratch.mit.edu';
@@ -66,7 +67,7 @@ export default appTarget => {
         simulateScratchDesktop ?
             <WrappedGui
                 canEditTitle
-                isScratchDesktop
+                platform={PLATFORM.DESKTOP}
                 showTelemetryModal
                 canSave={false}
                 onTelemetryModalCancel={handleTelemetryModalCancel}
diff --git a/packages/scratch-gui/test/unit/components/cards.test.jsx b/packages/scratch-gui/test/unit/components/cards.test.jsx
index 81ec23bc8f..2f0d5c4220 100644
--- a/packages/scratch-gui/test/unit/components/cards.test.jsx
+++ b/packages/scratch-gui/test/unit/components/cards.test.jsx
@@ -1,5 +1,6 @@
 import React from 'react';
 import {mountWithIntl} from '../../helpers/intl-helpers.jsx';
+import {PLATFORM} from '../../../src/lib/platform.js';
 
 // Mock this utility because it uses dynamic imports that do not work with jest
 jest.mock('../../../src/lib/libraries/decks/translate-image.js', () => {});
@@ -39,7 +40,7 @@ describe('Cards component', () => {
         const component = mountWithIntl(
             <Cards
                 {...defaultProps()}
-                platform="WEB"
+                platform={PLATFORM.WEB}
                 showVideos
             />
         );
diff --git a/packages/scratch-gui/test/unit/components/menu-bar.test.jsx b/packages/scratch-gui/test/unit/components/menu-bar.test.jsx
index f3ab1c593d..190e776c65 100644
--- a/packages/scratch-gui/test/unit/components/menu-bar.test.jsx
+++ b/packages/scratch-gui/test/unit/components/menu-bar.test.jsx
@@ -5,6 +5,8 @@ import {menuInitialState} from '../../../src/reducers/menus';
 import {LoadingState} from '../../../src/reducers/project-state';
 import {DEFAULT_THEME} from '../../../src/lib/themes';
 
+import {PLATFORM} from '../../../src/lib/platform';
+
 import configureStore from 'redux-mock-store';
 import {Provider} from 'react-redux';
 import VM from '@scratch/scratch-vm';
@@ -26,7 +28,10 @@ describe('MenuBar Component', () => {
             timeTravel: {
                 year: 'NOW'
             },
-            vm: new VM()
+            vm: new VM(),
+            platform: {
+                platform: PLATFORM.WEB
+            }
         }
     });
 
diff --git a/packages/scratch-gui/webpack.config.js b/packages/scratch-gui/webpack.config.js
index 6a547e87d9..07277d0329 100644
--- a/packages/scratch-gui/webpack.config.js
+++ b/packages/scratch-gui/webpack.config.js
@@ -99,6 +99,11 @@ const distConfig = baseConfig.clone()
             'scratch-gui': path.join(__dirname, 'src/index.ts')
         },
         output: {
+            // We need the public path to be relative, because of scratch-desktop and scratch-android
+            // - if the publicPath is static here (defaults to `/`), they are unable to load their assets,
+            // which depend on a relative path resolution.
+            // (e.g. `/tmp/*path-to-packaged-dist*/static/assets` in scratch-desktop)
+            publicPath: 'auto',
             path: path.resolve(__dirname, 'dist')
         }
     })
diff --git a/packages/scratch-render/package.json b/packages/scratch-render/package.json
index 1e4d0bc1a1..733b2d2605 100644
--- a/packages/scratch-render/package.json
+++ b/packages/scratch-render/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@scratch/scratch-render",
-  "version": "11.0.0",
+  "version": "11.1.0",
   "description": "WebGL Renderer for Scratch 3.0",
   "author": "Massachusetts Institute of Technology",
   "license": "AGPL-3.0-only",
@@ -47,7 +47,7 @@
     "iOS >= 8"
   ],
   "dependencies": {
-    "@scratch/scratch-svg-renderer": "11.0.0",
+    "@scratch/scratch-svg-renderer": "11.1.0",
     "grapheme-breaker": "0.3.2",
     "hull.js": "0.2.10",
     "ify-loader": "1.1.0",
@@ -64,7 +64,7 @@
     "@babel/eslint-parser": "7.27.0",
     "@babel/polyfill": "7.12.1",
     "@babel/preset-env": "7.26.9",
-    "@scratch/scratch-vm": "11.0.0",
+    "@scratch/scratch-vm": "11.1.0",
     "babel-loader": "9.2.1",
     "copy-webpack-plugin": "6.4.1",
     "docdash": "0.4.0",
@@ -75,9 +75,9 @@
     "jsdoc": "3.6.11",
     "json": "9.0.6",
     "playwright-chromium": "1.51.1",
-    "scratch-render-fonts": "1.0.180",
+    "scratch-render-fonts": "1.0.182",
     "scratch-semantic-release-config": "3.0.0",
-    "scratch-storage": "4.0.95",
+    "scratch-storage": "4.0.106",
     "scratch-webpack-configuration": "3.0.0",
     "semantic-release": "19.0.5",
     "tap": "16.3.10",
diff --git a/packages/scratch-svg-renderer/package.json b/packages/scratch-svg-renderer/package.json
index ce25d80dc5..e1c91585a9 100644
--- a/packages/scratch-svg-renderer/package.json
+++ b/packages/scratch-svg-renderer/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@scratch/scratch-svg-renderer",
-  "version": "11.0.0",
+  "version": "11.1.0",
   "description": "SVG renderer for Scratch",
   "main": "./dist/node/scratch-svg-renderer.js",
   "browser": "./dist/web/scratch-svg-renderer.js",
@@ -61,7 +61,7 @@
     "json": "9.0.6",
     "mkdirp": "2.1.6",
     "rimraf": "3.0.2",
-    "scratch-render-fonts": "1.0.180",
+    "scratch-render-fonts": "1.0.182",
     "scratch-semantic-release-config": "3.0.0",
     "scratch-webpack-configuration": "3.0.0",
     "semantic-release": "19.0.5",
diff --git a/packages/scratch-vm/package.json b/packages/scratch-vm/package.json
index 346c7ff71c..3818518ba9 100644
--- a/packages/scratch-vm/package.json
+++ b/packages/scratch-vm/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@scratch/scratch-vm",
-  "version": "11.0.0",
+  "version": "11.1.0",
   "description": "Virtual Machine for Scratch 3.0",
   "author": "Massachusetts Institute of Technology",
   "license": "AGPL-3.0-only",
@@ -50,8 +50,8 @@
     "statements": 70
   },
   "dependencies": {
-    "@scratch/scratch-render": "11.0.0",
-    "@scratch/scratch-svg-renderer": "11.0.0",
+    "@scratch/scratch-render": "11.1.0",
+    "@scratch/scratch-svg-renderer": "11.1.0",
     "@vernier/godirect": "1.8.3",
     "arraybuffer-loader": "1.0.8",
     "atob": "2.1.2",
@@ -64,10 +64,10 @@
     "immutable": "3.8.2",
     "jszip": "3.10.1",
     "minilog": "3.1.0",
-    "scratch-audio": "2.0.110",
+    "scratch-audio": "2.0.119",
     "scratch-parser": "6.0.0",
-    "scratch-sb1-converter": "2.0.99",
-    "scratch-storage": "4.0.95",
+    "scratch-sb1-converter": "2.0.107",
+    "scratch-storage": "4.0.106",
     "scratch-translate-extension-languages": "1.0.7",
     "text-encoding": "0.7.0",
     "uuid": "8.3.2",
@@ -92,9 +92,9 @@
     "jsdoc": "3.6.11",
     "json": "^9.0.4",
     "pngjs": "3.4.0",
-    "scratch-blocks": "1.1.206",
-    "scratch-l10n": "5.0.184",
-    "scratch-render-fonts": "1.0.180",
+    "scratch-blocks": "1.1.209",
+    "scratch-l10n": "5.0.198",
+    "scratch-render-fonts": "1.0.182",
     "scratch-semantic-release-config": "3.0.0",
     "scratch-webpack-configuration": "3.0.0",
     "script-loader": "0.7.2",