diff --git a/package-lock.json b/package-lock.json
index 2f4b644a917..eed278feb7b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,11 @@
"license": "AGPL-3.0-only",
"dependencies": {
"@microbit/microbit-universal-hex": "^0.2.2",
+ "@types/node": "^22.13.14",
+ "@webcontainer/api": "^1.5.3",
+ "abstract-syntax-tree": "^2.22.0",
+ "ace-builds": "^1.39.1",
+ "ace-linters": "^1.5.2",
"arraybuffer-loader": "^1.0.6",
"autoprefixer": "^9.0.1",
"balance-text": "^3.3.1",
@@ -25,6 +30,7 @@
"dapjs": "^2.3.0",
"es6-object-assign": "^1.1.0",
"fastestsmallesttextencoderdecoder": "^1.0.22",
+ "fs": "^0.0.1-security",
"get-float-time-domain-data": "^0.1.0",
"get-user-media-promise": "^1.1.4",
"immutable": "^3.8.2",
@@ -39,12 +45,14 @@
"minilog": "^3.1.0",
"omggif": "^1.0.9",
"papaparse": "^5.3.0",
+ "path": "^0.12.7",
"postcss-import": "^12.0.0",
"postcss-loader": "4.3.0",
"postcss-simple-vars": "^5.0.1",
"prop-types": "^15.5.10",
"query-string": "^5.1.1",
"raw-loader": "^4.0.0",
+ "react-ace": "^14.0.1",
"react-contextmenu": "^2.9.4",
"react-draggable": "^3.0.5",
"react-ga": "^2.5.3",
@@ -59,6 +67,7 @@
"react-virtualized": "^9.20.1",
"redux": "^3.7.2",
"redux-throttle": "^0.1.1",
+ "request": "^2.88.2",
"scratch-audio": "^2.0.0",
"scratch-blocks": "^1.1.6",
"scratch-l10n": "^5.0.0",
@@ -68,9 +77,12 @@
"scratch-storage": "^4.0.0",
"scratch-svg-renderer": "^3.0.0",
"scratch-vm": "^5.0.0",
+ "scratch-vm-local": "file:../scratch-vm-local",
"startaudiocontext": "^1.2.1",
"style-loader": "4.0.0",
"to-style": "^1.3.3",
+ "ts-node": "^10.9.2",
+ "uuid": "^11.1.0",
"wav-encoder": "^1.3.0",
"xhr": "^2.5.0"
},
@@ -2039,6 +2051,12 @@
"node": ">=v14"
}
},
+ "node_modules/@commitlint/load/node_modules/@types/node": {
+ "version": "20.5.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz",
+ "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==",
+ "dev": true
+ },
"node_modules/@commitlint/message": {
"version": "17.8.1",
"resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.8.1.tgz",
@@ -2156,7 +2174,6 @@
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
@@ -2169,7 +2186,6 @@
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
@@ -3270,28 +3286,24 @@
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
- "dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
- "dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
- "dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
- "dev": true,
"license": "MIT"
},
"node_modules/@types/babel__core": {
@@ -3522,10 +3534,12 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "20.5.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz",
- "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==",
- "license": "MIT"
+ "version": "22.13.14",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.14.tgz",
+ "integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
},
"node_modules/@types/node-forge": {
"version": "1.3.11",
@@ -3897,6 +3911,11 @@
"@xtuc/long": "4.2.2"
}
},
+ "node_modules/@webcontainer/api": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/@webcontainer/api/-/api-1.5.3.tgz",
+ "integrity": "sha512-f6Oq3ohtSC5RYABhpN8aVOVHpcKvJ1fB1jjuvODTBU5u6BcroYEhphnrywdw8RO+2Vy5ekCdKe5D4dCMdMSrzA=="
+ },
"node_modules/@webpack-cli/configtest": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz",
@@ -3964,6 +3983,30 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/abstract-syntax-tree": {
+ "version": "2.22.0",
+ "resolved": "https://registry.npmjs.org/abstract-syntax-tree/-/abstract-syntax-tree-2.22.0.tgz",
+ "integrity": "sha512-Px1YA1lvdQN/DGqyZ4rIp6LH8mEtRcyFYZw48cYQ/fK0r7QffIPkEV2ob3g804aS9OjUwuKoqhPTKb3kvZVhug==",
+ "dependencies": {
+ "ast-types": "0.14.2",
+ "astring": "^1.8.6",
+ "esquery": "^1.5.0",
+ "meriyah": "^4.4.0",
+ "pure-conditions": "^1.2.1",
+ "source-map": "^0.7.4"
+ },
+ "engines": {
+ "node": ">=20.11.1"
+ }
+ },
+ "node_modules/abstract-syntax-tree/node_modules/source-map": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+ "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -3988,6 +4031,21 @@
"node": ">= 0.6"
}
},
+ "node_modules/ace-builds": {
+ "version": "1.39.1",
+ "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.39.1.tgz",
+ "integrity": "sha512-HcJbBzx8qY66t9gZo/sQu7pi0wO/CFLdYn1LxQO1WQTfIkMfyc7LRnBpsp/oNCSSU/LL83jXHN1fqyOTuIhUjg=="
+ },
+ "node_modules/ace-linters": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/ace-linters/-/ace-linters-1.5.2.tgz",
+ "integrity": "sha512-ZMDyQgZCjo29ZzR/qKm+BnnF+x6GRlVK8a4EDc1A96htr7Qnx/mgUHJEV0KoCTO1E4TKYEdwOJ/DCFUWpDIY2Q==",
+ "dependencies": {
+ "vscode-languageserver-protocol": "^3.17.5",
+ "vscode-languageserver-textdocument": "^1.0.8",
+ "vscode-languageserver-types": "^3.17.3"
+ }
+ },
"node_modules/acorn": {
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
@@ -4037,7 +4095,6 @@
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.11.0"
@@ -4255,7 +4312,6 @@
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
- "dev": true,
"license": "MIT"
},
"node_modules/argparse": {
@@ -4660,6 +4716,17 @@
"node": ">=0.10.0"
}
},
+ "node_modules/ast-types": {
+ "version": "0.14.2",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz",
+ "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==",
+ "dependencies": {
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/astral-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
@@ -4670,6 +4737,14 @@
"node": ">=4"
}
},
+ "node_modules/astring": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz",
+ "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==",
+ "bin": {
+ "astring": "bin/astring"
+ }
+ },
"node_modules/async": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
@@ -7379,7 +7454,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/cross-fetch": {
@@ -9686,7 +9760,6 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
- "dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"estraverse": "^5.1.0"
@@ -10905,6 +10978,11 @@
],
"license": "MIT"
},
+ "node_modules/fs": {
+ "version": "0.0.1-security",
+ "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
+ "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w=="
+ },
"node_modules/fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -17413,12 +17491,17 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
+ "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead."
+ },
"node_modules/lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
- "dev": true,
"license": "MIT"
},
"node_modules/lodash.isfunction": {
@@ -17615,7 +17698,6 @@
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "dev": true,
"license": "ISC"
},
"node_modules/makeerror": {
@@ -17921,6 +18003,14 @@
"node": ">= 8"
}
},
+ "node_modules/meriyah": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/meriyah/-/meriyah-4.5.0.tgz",
+ "integrity": "sha512-Rbiu0QPIxTXgOXwiIpRVJfZRQ2FWyfzYrOGBs9SN5RbaXg1CN5ELn/plodwWwluX93yzc4qO/bNIen1ThGFCxw==",
+ "engines": {
+ "node": ">=10.4.0"
+ }
+ },
"node_modules/methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
@@ -22325,6 +22415,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/path": {
+ "version": "0.12.7",
+ "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
+ "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==",
+ "dependencies": {
+ "process": "^0.11.1",
+ "util": "^0.10.3"
+ }
+ },
"node_modules/path-browserify": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
@@ -22382,6 +22481,19 @@
"node": ">=8"
}
},
+ "node_modules/path/node_modules/inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="
+ },
+ "node_modules/path/node_modules/util": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
+ "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
+ "dependencies": {
+ "inherits": "2.0.3"
+ }
+ },
"node_modules/pbkdf2": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
@@ -23224,6 +23336,11 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/pure-conditions": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/pure-conditions/-/pure-conditions-1.2.1.tgz",
+ "integrity": "sha512-MKk7sKQiR3Fe3bL/QedUZ1eVoNO0xpOCyiTGdVrK+4ZCDa9TgwNp6D/U1FthjhVGS9a857BS84WncvZvOYECUw=="
+ },
"node_modules/q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
@@ -23584,6 +23701,22 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-ace": {
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-14.0.1.tgz",
+ "integrity": "sha512-z6YAZ20PNf/FqmYEic//G/UK6uw0rn21g58ASgHJHl9rfE4nITQLqthr9rHMVQK4ezwohJbp2dGrZpkq979PYQ==",
+ "dependencies": {
+ "ace-builds": "^1.36.3",
+ "diff-match-patch": "^1.0.5",
+ "lodash.get": "^4.4.2",
+ "lodash.isequal": "^4.5.0",
+ "prop-types": "^15.8.1"
+ },
+ "peerDependencies": {
+ "react": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/react-contextmenu": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/react-contextmenu/-/react-contextmenu-2.14.0.tgz",
@@ -23834,6 +23967,14 @@
"react-dom": ">=16.0.0"
}
},
+ "node_modules/react-tooltip/node_modules/uuid": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
+ "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/react-virtualized": {
"version": "9.22.6",
"resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.6.tgz",
@@ -24540,7 +24681,6 @@
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
- "license": "Apache-2.0",
"dependencies": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
@@ -25555,10 +25695,9 @@
}
},
"node_modules/scratch-svg-renderer": {
- "version": "3.0.73",
- "resolved": "https://registry.npmjs.org/scratch-svg-renderer/-/scratch-svg-renderer-3.0.73.tgz",
- "integrity": "sha512-1PTEXIwn0Y6Ib6dy0kSkdIXqVkt30TCfBGxQrJClaHrq1XGEBH/M92Hc2hSvwXRYLX30GrALT0o5SLWGJTw8EA==",
- "license": "AGPL-3.0-only",
+ "version": "3.0.75",
+ "resolved": "https://registry.npmjs.org/scratch-svg-renderer/-/scratch-svg-renderer-3.0.75.tgz",
+ "integrity": "sha512-/vsDEBgcuxkhvx2YbgQLSS/yFclWCkwxyhUJ5t2D/+RZOkAY0Iv5oIp32I+bEkYe3pNNW1g55z7vi48jAYY47A==",
"dependencies": {
"base64-js": "^1.2.1",
"base64-loader": "^1.0.0",
@@ -25579,9 +25718,38 @@
"license": "BSD-3-Clause"
},
"node_modules/scratch-vm": {
- "version": "5.0.198",
- "resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-5.0.198.tgz",
- "integrity": "sha512-nH8hBHSGZY1C7/GDs4Bf2Bt6NRD2WaFB4XGYr8zB4Uj8koOmUknB+5bl0qjNHpO1LIef9vXhSzbY6DXJy37UQA==",
+ "version": "5.0.206",
+ "resolved": "file:../scratch-vm",
+ "license": "AGPL-3.0-only",
+ "dependencies": {
+ "@vernier/godirect": "^1.5.0",
+ "arraybuffer-loader": "^1.0.6",
+ "atob": "^2.1.2",
+ "btoa": "^1.2.1",
+ "buffer": "^6.0.3",
+ "canvas-toBlob": "^1.0.0",
+ "decode-html": "^2.0.0",
+ "diff-match-patch": "^1.0.4",
+ "format-message": "^6.2.1",
+ "htmlparser2": "^3.10.0",
+ "immutable": "^3.8.1",
+ "jszip": "^3.1.5",
+ "minilog": "^3.1.0",
+ "scratch-audio": "^2.0.0",
+ "scratch-parser": "^6.0.0",
+ "scratch-render": "^2.0.0",
+ "scratch-sb1-converter": "^2.0.0",
+ "scratch-storage": "^4.0.0",
+ "scratch-svg-renderer": "3.0.75",
+ "scratch-translate-extension-languages": "^1.0.0",
+ "text-encoding": "^0.7.0",
+ "uuid": "^8.3.2",
+ "web-worker": "^1.3.0"
+ }
+ },
+ "node_modules/scratch-vm-local": {
+ "version": "5.0.206",
+ "resolved": "file:../scratch-vm-local",
"license": "AGPL-3.0-only",
"dependencies": {
"@vernier/godirect": "^1.5.0",
@@ -25602,13 +25770,44 @@
"scratch-render": "^2.0.0",
"scratch-sb1-converter": "^2.0.0",
"scratch-storage": "^4.0.0",
- "scratch-svg-renderer": "3.0.73",
+ "scratch-svg-renderer": "3.0.75",
"scratch-translate-extension-languages": "^1.0.0",
"text-encoding": "^0.7.0",
"uuid": "^8.3.2",
"web-worker": "^1.3.0"
}
},
+ "node_modules/scratch-vm-local/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/scratch-vm-local/node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/scratch-vm/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
@@ -28516,8 +28715,6 @@
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
- "dev": true,
- "license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -28560,7 +28757,6 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
@@ -28767,7 +28963,6 @@
"version": "5.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
- "dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
@@ -28844,6 +29039,11 @@
"ieee754": "^1.1.13"
}
},
+ "node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
+ },
"node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
@@ -29298,19 +29498,21 @@
}
},
"node_modules/uuid": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
- "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
- "license": "MIT",
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
+ "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
"bin": {
- "uuid": "dist/bin/uuid"
+ "uuid": "dist/esm/bin/uuid"
}
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
- "dev": true,
"license": "MIT"
},
"node_modules/validate-npm-package-license": {
@@ -29360,6 +29562,33 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/vscode-jsonrpc": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
+ "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/vscode-languageserver-protocol": {
+ "version": "3.17.5",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
+ "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
+ "dependencies": {
+ "vscode-jsonrpc": "8.2.0",
+ "vscode-languageserver-types": "3.17.5"
+ }
+ },
+ "node_modules/vscode-languageserver-textdocument": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz",
+ "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA=="
+ },
+ "node_modules/vscode-languageserver-types": {
+ "version": "3.17.5",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
+ "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
+ },
"node_modules/w3c-xmlserializer": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
@@ -30146,7 +30375,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
diff --git a/package.json b/package.json
index 3c277f3d8d2..c1cc2139afb 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,11 @@
},
"dependencies": {
"@microbit/microbit-universal-hex": "^0.2.2",
+ "@types/node": "^22.13.14",
+ "@webcontainer/api": "^1.5.3",
+ "abstract-syntax-tree": "^2.22.0",
+ "ace-builds": "^1.39.1",
+ "ace-linters": "^1.5.2",
"arraybuffer-loader": "^1.0.6",
"autoprefixer": "^9.0.1",
"balance-text": "^3.3.1",
@@ -48,6 +53,7 @@
"dapjs": "^2.3.0",
"es6-object-assign": "^1.1.0",
"fastestsmallesttextencoderdecoder": "^1.0.22",
+ "fs": "^0.0.1-security",
"get-float-time-domain-data": "^0.1.0",
"get-user-media-promise": "^1.1.4",
"immutable": "^3.8.2",
@@ -62,12 +68,14 @@
"minilog": "^3.1.0",
"omggif": "^1.0.9",
"papaparse": "^5.3.0",
+ "path": "^0.12.7",
"postcss-import": "^12.0.0",
"postcss-loader": "4.3.0",
"postcss-simple-vars": "^5.0.1",
"prop-types": "^15.5.10",
"query-string": "^5.1.1",
"raw-loader": "^4.0.0",
+ "react-ace": "^14.0.1",
"react-contextmenu": "^2.9.4",
"react-draggable": "^3.0.5",
"react-ga": "^2.5.3",
@@ -82,6 +90,7 @@
"react-virtualized": "^9.20.1",
"redux": "^3.7.2",
"redux-throttle": "^0.1.1",
+ "request": "^2.88.2",
"scratch-audio": "^2.0.0",
"scratch-blocks": "^1.1.6",
"scratch-l10n": "^5.0.0",
@@ -91,9 +100,12 @@
"scratch-storage": "^4.0.0",
"scratch-svg-renderer": "^3.0.0",
"scratch-vm": "^5.0.0",
+ "scratch-vm-local": "file:../scratch-vm-local",
"startaudiocontext": "^1.2.1",
"style-loader": "4.0.0",
"to-style": "^1.3.3",
+ "ts-node": "^10.9.2",
+ "uuid": "^11.1.0",
"wav-encoder": "^1.3.0",
"xhr": "^2.5.0"
},
diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx
index f2d0a8e8f73..851deee2f0b 100644
--- a/src/components/gui/gui.jsx
+++ b/src/components/gui/gui.jsx
@@ -1,11 +1,10 @@
import classNames from 'classnames';
import omit from 'lodash.omit';
import PropTypes from 'prop-types';
-import React from 'react';
-import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl';
-import {connect} from 'react-redux';
+import { defineMessages, FormattedMessage, injectIntl, intlShape } from 'react-intl';
+import { connect } from 'react-redux';
import MediaQuery from 'react-responsive';
-import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
+import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import tabStyles from 'react-tabs/style/react-tabs.css';
import VM from 'scratch-vm';
import Renderer from 'scratch-render';
@@ -31,9 +30,9 @@ import DragLayer from '../../containers/drag-layer.jsx';
import ConnectionModal from '../../containers/connection-modal.jsx';
import TelemetryModal from '../telemetry-modal/telemetry-modal.jsx';
-import layout, {STAGE_SIZE_MODES} from '../../lib/layout-constants';
-import {resolveStageSize} from '../../lib/screen-utils';
-import {themeMap} from '../../lib/themes';
+import layout, { STAGE_SIZE_MODES } from '../../lib/layout-constants';
+import { resolveStageSize } from '../../lib/screen-utils';
+import { themeMap } from '../../lib/themes';
import styles from './gui.css';
import addExtensionIcon from './icon--extensions.svg';
@@ -41,443 +40,575 @@ import codeIcon from './icon--code.svg';
import costumesIcon from './icon--costumes.svg';
import soundsIcon from './icon--sounds.svg';
import DebugModal from '../debug-modal/debug-modal.jsx';
+import { useEffect } from 'react';
+import { WebContainer } from '@webcontainer/api';
+
+
+import React, { useState } from 'react';
+import AceEditor from 'react-ace';
+import 'ace-builds/src-noconflict/mode-javascript';
+import 'ace-builds/src-noconflict/theme-monokai';
+import 'ace-builds/webpack-resolver';
+
+// import VM2 from 'scratch-vm-local';
+
+// const { Runtime, Motion, Sprite, RenderedTarget } = VM2.EngineFunctions;
+
+// function TestMotion() {
+// const rt = new Runtime();
+// const motion = new Motion(rt);
+// const sprite = new Sprite(null, rt);
+// const target = new RenderedTarget(sprite, rt);
+// const util = { target };
+
+// motion.goToXY({ X: 0.999999999, Y: 0.999999999 }, util);
+// }
+
+function CodeEditor(props) {
+ const [files, setFiles] = useState({
+ 'sprite1.js': `
+ export function run (ctx, target, MathUtil) {
+ ctx.on("KEY_PRESSED", function (key) {
+ if(key === "right arrow") {
+ const steps = 10;
+ const radians = MathUtil.degToRad(90 - target.direction);
+ const dx = steps * Math.cos(radians);
+ const dy = steps * Math.sin(radians);
+ target.setXY(target.x + dx, target.y + dy);
+ }
+ });
+ }
+ `,
+
+ 'sprite2.js': ``,
+ 'common.js': ``,
+ });
+ const [activeFile, setActiveFile] = useState('game.js');
+
+ const handleChange = (newCode) => {
+ // Update the content of the active file
+ setFiles((prevFiles) => ({
+ ...prevFiles,
+ [activeFile]: newCode,
+ }));
+ };
+
+ const handleTabClick = (fileName) => {
+ setActiveFile(fileName);
+ };
+
+ const insertEventListenerKeys = (targetId, code) => {
+ return code.replace(`ctx.on(`, `ctx.onWithKey(\"${targetId}\", `);
+ }
+
+ useEffect(() => {
+
+ console.log(props.vm);
+ }, []);
+
+ return (
+
+
+ {/* File Tabs */}
+
+ {Object.keys(files).map((fileName) => (
+
+ ))}
+
+
+ {/* Ace Editor */}
+
+
+ );
+}
const messages = defineMessages({
- addExtension: {
- id: 'gui.gui.addExtension',
- description: 'Button to add an extension in the target pane',
- defaultMessage: 'Add Extension'
- }
+ addExtension: {
+ id: 'gui.gui.addExtension',
+ description: 'Button to add an extension in the target pane',
+ defaultMessage: 'Add Extension'
+ }
});
+let webcontainerInstance;
+
+// await webcontainerInstance.mount(files);
+
// Cache this value to only retrieve it once the first time.
// Assume that it doesn't change for a session.
let isRendererSupported = null;
const GUIComponent = props => {
- const {
- accountNavOpen,
- activeTabIndex,
- alertsVisible,
- authorId,
- authorThumbnailUrl,
- authorUsername,
- basePath,
- backdropLibraryVisible,
- backpackHost,
- backpackVisible,
- blocksId,
- blocksTabVisible,
- cardsVisible,
- canChangeLanguage,
- canChangeTheme,
- canCreateNew,
- canEditTitle,
- canManageFiles,
- canRemix,
- canSave,
- canCreateCopy,
- canShare,
- canUseCloud,
- children,
- connectionModalVisible,
- costumeLibraryVisible,
- costumesTabVisible,
- debugModalVisible,
- enableCommunity,
- intl,
- isCreating,
- isFullScreen,
- isPlayerOnly,
- isRtl,
- isShared,
- isTelemetryEnabled,
- isTotallyNormal,
- loading,
- logo,
- renderLogin,
- onClickAbout,
- onClickAccountNav,
- onCloseAccountNav,
- onLogOut,
- onOpenRegistration,
- onToggleLoginOpen,
- onActivateCostumesTab,
- onActivateSoundsTab,
- onActivateTab,
- onClickLogo,
- onExtensionButtonClick,
- onProjectTelemetryEvent,
- onRequestCloseBackdropLibrary,
- onRequestCloseCostumeLibrary,
- onRequestCloseDebugModal,
- onRequestCloseTelemetryModal,
- onSeeCommunity,
- onShare,
- onShowPrivacyPolicy,
- onStartSelectingFileUpload,
- onTelemetryModalCancel,
- onTelemetryModalOptIn,
- onTelemetryModalOptOut,
- showComingSoon,
- soundsTabVisible,
- stageSizeMode,
- targetIsStage,
- telemetryModalVisible,
- theme,
- tipsLibraryVisible,
- vm,
- ...componentProps
- } = omit(props, 'dispatch');
- if (children) {
- return {children};
- }
-
- const tabClassNames = {
- tabs: styles.tabs,
- tab: classNames(tabStyles.reactTabsTab, styles.tab),
- tabList: classNames(tabStyles.reactTabsTabList, styles.tabList),
- tabPanel: classNames(tabStyles.reactTabsTabPanel, styles.tabPanel),
- tabPanelSelected: classNames(tabStyles.reactTabsTabPanelSelected, styles.isSelected),
- tabSelected: classNames(tabStyles.reactTabsTabSelected, styles.isSelected)
- };
-
- if (isRendererSupported === null) {
- isRendererSupported = Renderer.isSupported();
- }
-
- return ({isFullSize => {
- const stageSize = resolveStageSize(stageSizeMode, isFullSize);
-
- return isPlayerOnly ? (
-
- {alertsVisible ? (
-
- ) : null}
-
- ) : (
-
- {telemetryModalVisible ? (
- {children};
+ }
+
+ const tabClassNames = {
+ tabs: styles.tabs,
+ tab: classNames(tabStyles.reactTabsTab, styles.tab),
+ tabList: classNames(tabStyles.reactTabsTabList, styles.tabList),
+ tabPanel: classNames(tabStyles.reactTabsTabPanel, styles.tabPanel),
+ tabPanelSelected: classNames(tabStyles.reactTabsTabPanelSelected, styles.isSelected),
+ tabSelected: classNames(tabStyles.reactTabsTabSelected, styles.isSelected)
+ };
+
+ if (isRendererSupported === null) {
+ isRendererSupported = Renderer.isSupported();
+ }
+
+
+ return ({isFullSize => {
+ const stageSize = resolveStageSize(stageSizeMode, isFullSize);
+
+ return isPlayerOnly ? (
+
+ {alertsVisible ? (
+
+ ) : null}
+
+ ) : (
+
+ {telemetryModalVisible ? (
+
+ ) : null}
+ {loading ? (
+
+ ) : null}
+ {isCreating ? (
+
+ ) : null}
+ {isRendererSupported ? null : (
+
+ )}
+ {tipsLibraryVisible ? (
+
+ ) : null}
+ {cardsVisible ? (
+
+ ) : null}
+ {alertsVisible ? (
+
+ ) : null}
+ {connectionModalVisible ? (
+
+ ) : null}
+ {costumeLibraryVisible ? (
+
+ ) : null}
+ {}
+ {backdropLibraryVisible ? (
+
+ ) : null}
+
+
+
+ {/*
+
+
+
+
+
- ) : null}
- {loading ? (
-
- ) : null}
- {isCreating ? (
-
- ) : null}
- {isRendererSupported ? null : (
-
- )}
- {tipsLibraryVisible ? (
-
- ) : null}
- {cardsVisible ? (
-
- ) : null}
- {alertsVisible ? (
-
- ) : null}
- {connectionModalVisible ? (
-
+
+
- ) : null}
- {costumeLibraryVisible ? (
-
+ ) : (
+
+ )}
+
+
+
- ) : null}
- {}
- {backdropLibraryVisible ? (
-
- ) : null}
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {costumesTabVisible ? : null}
+
+
+ {soundsTabVisible ? : null}
+
+
+ {backpackVisible ? (
+
+ ) : null}
+ */}
+
+
+
+
Editor
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
- {targetIsStage ? (
-
- ) : (
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {costumesTabVisible ? : null}
-
-
- {soundsTabVisible ? : null}
-
-
- {backpackVisible ? (
-
- ) : null}
-
-
-
-
-
-
-
-
-
-
-
+
- );
- }});
+
+
+
+
+ );
+ }});
};
GUIComponent.propTypes = {
- accountNavOpen: PropTypes.bool,
- activeTabIndex: PropTypes.number,
- authorId: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), // can be false
- authorThumbnailUrl: PropTypes.string,
- authorUsername: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), // can be false
- backdropLibraryVisible: PropTypes.bool,
- backpackHost: PropTypes.string,
- backpackVisible: PropTypes.bool,
- basePath: PropTypes.string,
- blocksTabVisible: PropTypes.bool,
- blocksId: PropTypes.string,
- canChangeLanguage: PropTypes.bool,
- canChangeTheme: PropTypes.bool,
- canCreateCopy: PropTypes.bool,
- canCreateNew: PropTypes.bool,
- canEditTitle: PropTypes.bool,
- canManageFiles: PropTypes.bool,
- canRemix: PropTypes.bool,
- canSave: PropTypes.bool,
- canShare: PropTypes.bool,
- canUseCloud: PropTypes.bool,
- cardsVisible: PropTypes.bool,
- children: PropTypes.node,
- costumeLibraryVisible: PropTypes.bool,
- costumesTabVisible: PropTypes.bool,
- debugModalVisible: PropTypes.bool,
- enableCommunity: PropTypes.bool,
- intl: intlShape.isRequired,
- isCreating: PropTypes.bool,
- isFullScreen: PropTypes.bool,
- isPlayerOnly: PropTypes.bool,
- isRtl: PropTypes.bool,
- isShared: PropTypes.bool,
- isTotallyNormal: PropTypes.bool,
- loading: PropTypes.bool,
- logo: PropTypes.string,
- onActivateCostumesTab: PropTypes.func,
- onActivateSoundsTab: PropTypes.func,
- onActivateTab: PropTypes.func,
- onClickAccountNav: PropTypes.func,
- onClickLogo: PropTypes.func,
- onCloseAccountNav: PropTypes.func,
- onExtensionButtonClick: PropTypes.func,
- onLogOut: PropTypes.func,
- onOpenRegistration: PropTypes.func,
- onRequestCloseBackdropLibrary: PropTypes.func,
- onRequestCloseCostumeLibrary: PropTypes.func,
- onRequestCloseDebugModal: PropTypes.func,
- onRequestCloseTelemetryModal: PropTypes.func,
- onSeeCommunity: PropTypes.func,
- onShare: PropTypes.func,
- onShowPrivacyPolicy: PropTypes.func,
- onStartSelectingFileUpload: PropTypes.func,
- onTabSelect: PropTypes.func,
- onTelemetryModalCancel: PropTypes.func,
- onTelemetryModalOptIn: PropTypes.func,
- onTelemetryModalOptOut: PropTypes.func,
- onToggleLoginOpen: PropTypes.func,
- renderLogin: PropTypes.func,
- showComingSoon: PropTypes.bool,
- soundsTabVisible: PropTypes.bool,
- stageSizeMode: PropTypes.oneOf(Object.keys(STAGE_SIZE_MODES)),
- targetIsStage: PropTypes.bool,
- telemetryModalVisible: PropTypes.bool,
- theme: PropTypes.string,
- tipsLibraryVisible: PropTypes.bool,
- vm: PropTypes.instanceOf(VM).isRequired
+ accountNavOpen: PropTypes.bool,
+ activeTabIndex: PropTypes.number,
+ authorId: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), // can be false
+ authorThumbnailUrl: PropTypes.string,
+ authorUsername: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), // can be false
+ backdropLibraryVisible: PropTypes.bool,
+ backpackHost: PropTypes.string,
+ backpackVisible: PropTypes.bool,
+ basePath: PropTypes.string,
+ blocksTabVisible: PropTypes.bool,
+ blocksId: PropTypes.string,
+ canChangeLanguage: PropTypes.bool,
+ canChangeTheme: PropTypes.bool,
+ canCreateCopy: PropTypes.bool,
+ canCreateNew: PropTypes.bool,
+ canEditTitle: PropTypes.bool,
+ canManageFiles: PropTypes.bool,
+ canRemix: PropTypes.bool,
+ canSave: PropTypes.bool,
+ canShare: PropTypes.bool,
+ canUseCloud: PropTypes.bool,
+ cardsVisible: PropTypes.bool,
+ children: PropTypes.node,
+ costumeLibraryVisible: PropTypes.bool,
+ costumesTabVisible: PropTypes.bool,
+ debugModalVisible: PropTypes.bool,
+ enableCommunity: PropTypes.bool,
+ intl: intlShape.isRequired,
+ isCreating: PropTypes.bool,
+ isFullScreen: PropTypes.bool,
+ isPlayerOnly: PropTypes.bool,
+ isRtl: PropTypes.bool,
+ isShared: PropTypes.bool,
+ isTotallyNormal: PropTypes.bool,
+ loading: PropTypes.bool,
+ logo: PropTypes.string,
+ onActivateCostumesTab: PropTypes.func,
+ onActivateSoundsTab: PropTypes.func,
+ onActivateTab: PropTypes.func,
+ onClickAccountNav: PropTypes.func,
+ onClickLogo: PropTypes.func,
+ onCloseAccountNav: PropTypes.func,
+ onExtensionButtonClick: PropTypes.func,
+ onLogOut: PropTypes.func,
+ onOpenRegistration: PropTypes.func,
+ onRequestCloseBackdropLibrary: PropTypes.func,
+ onRequestCloseCostumeLibrary: PropTypes.func,
+ onRequestCloseDebugModal: PropTypes.func,
+ onRequestCloseTelemetryModal: PropTypes.func,
+ onSeeCommunity: PropTypes.func,
+ onShare: PropTypes.func,
+ onShowPrivacyPolicy: PropTypes.func,
+ onStartSelectingFileUpload: PropTypes.func,
+ onTabSelect: PropTypes.func,
+ onTelemetryModalCancel: PropTypes.func,
+ onTelemetryModalOptIn: PropTypes.func,
+ onTelemetryModalOptOut: PropTypes.func,
+ onToggleLoginOpen: PropTypes.func,
+ renderLogin: PropTypes.func,
+ showComingSoon: PropTypes.bool,
+ soundsTabVisible: PropTypes.bool,
+ stageSizeMode: PropTypes.oneOf(Object.keys(STAGE_SIZE_MODES)),
+ targetIsStage: PropTypes.bool,
+ telemetryModalVisible: PropTypes.bool,
+ theme: PropTypes.string,
+ tipsLibraryVisible: PropTypes.bool,
+ vm: PropTypes.instanceOf(VM).isRequired
};
GUIComponent.defaultProps = {
- backpackHost: null,
- backpackVisible: false,
- basePath: './',
- blocksId: 'original',
- canChangeLanguage: true,
- canChangeTheme: true,
- canCreateNew: false,
- canEditTitle: false,
- canManageFiles: true,
- canRemix: false,
- canSave: false,
- canCreateCopy: false,
- canShare: false,
- canUseCloud: false,
- enableCommunity: false,
- isCreating: false,
- isShared: false,
- isTotallyNormal: false,
- loading: false,
- showComingSoon: false,
- stageSizeMode: STAGE_SIZE_MODES.large
+ backpackHost: null,
+ backpackVisible: false,
+ basePath: './',
+ blocksId: 'original',
+ canChangeLanguage: true,
+ canChangeTheme: true,
+ canCreateNew: false,
+ canEditTitle: false,
+ canManageFiles: true,
+ canRemix: false,
+ canSave: false,
+ canCreateCopy: false,
+ canShare: false,
+ canUseCloud: false,
+ enableCommunity: false,
+ isCreating: false,
+ isShared: false,
+ isTotallyNormal: false,
+ loading: false,
+ showComingSoon: false,
+ stageSizeMode: STAGE_SIZE_MODES.large
};
const mapStateToProps = state => ({
- // This is the button's mode, as opposed to the actual current state
- blocksId: state.scratchGui.timeTravel.year.toString(),
- stageSizeMode: state.scratchGui.stageSize.stageSize,
- theme: state.scratchGui.theme.theme
+ // This is the button's mode, as opposed to the actual current state
+ blocksId: state.scratchGui.timeTravel.year.toString(),
+ stageSizeMode: state.scratchGui.stageSize.stageSize,
+ theme: state.scratchGui.theme.theme
});
export default injectIntl(connect(
- mapStateToProps
+ mapStateToProps
)(GUIComponent));
diff --git a/src/lib/backpack-api.js b/src/lib/backpack-api.js
index 37a0aded036..af2d24065b4 100644
--- a/src/lib/backpack-api.js
+++ b/src/lib/backpack-api.js
@@ -8,80 +8,82 @@ import codePayload from './backpack/code-payload';
// Also include a full body url for loading sprite zips
// TODO retreiving the images through storage would allow us to remove this.
const includeFullUrls = (item, host) => Object.assign({}, item, {
- thumbnailUrl: `${host}/${item.thumbnail}`,
- bodyUrl: `${host}/${item.body}`
+ thumbnailUrl: `${host}/${item.thumbnail}`,
+ bodyUrl: `${host}/${item.body}`
});
const getBackpackContents = ({
- host,
- username,
- token,
- limit,
- offset
+ host,
+ username,
+ token,
+ limit,
+ offset
}) => new Promise((resolve, reject) => {
- xhr({
- method: 'GET',
- uri: `${host}/${username}?limit=${limit}&offset=${offset}`,
- headers: {'x-token': token},
- json: true
- }, (error, response) => {
- if (error || response.statusCode !== 200) {
- return reject(new Error(response.status));
- }
- return resolve(response.body.map(item => includeFullUrls(item, host)));
- });
+ xhr({
+ method: 'GET',
+ uri: `${host}/${username}?limit=${limit}&offset=${offset}`,
+ headers: {
+ 'x-token': token
+ },
+ json: true
+ }, (error, response) => {
+ if (error || response.statusCode !== 200) {
+ return reject(new Error(response.status));
+ }
+ return resolve(response.body.map(item => includeFullUrls(item, host)));
+ });
});
const saveBackpackObject = ({
- host,
- username,
- token,
- type, // Type of object being saved to the backpack
- mime, // Mime-type of the object being saved
- name, // User-facing name of the object being saved
- body, // Base64-encoded body of the object being saved
- thumbnail // Base64-encoded JPEG thumbnail of the object being saved
+ host,
+ username,
+ token,
+ type, // Type of object being saved to the backpack
+ mime, // Mime-type of the object being saved
+ name, // User-facing name of the object being saved
+ body, // Base64-encoded body of the object being saved
+ thumbnail // Base64-encoded JPEG thumbnail of the object being saved
}) => new Promise((resolve, reject) => {
- xhr({
- method: 'POST',
- uri: `${host}/${username}`,
- headers: {'x-token': token},
- json: {type, mime, name, body, thumbnail}
- }, (error, response) => {
- if (error || response.statusCode !== 200) {
- return reject(new Error(response.status));
- }
- return resolve(includeFullUrls(response.body, host));
- });
+ xhr({
+ method: 'POST',
+ uri: `${host}/${username}`,
+ headers: { 'x-token': token },
+ json: { type, mime, name, body, thumbnail }
+ }, (error, response) => {
+ if (error || response.statusCode !== 200) {
+ return reject(new Error(response.status));
+ }
+ return resolve(includeFullUrls(response.body, host));
+ });
});
const deleteBackpackObject = ({
- host,
- username,
- token,
- id
+ host,
+ username,
+ token,
+ id
}) => new Promise((resolve, reject) => {
- xhr({
- method: 'DELETE',
- uri: `${host}/${username}/${id}`,
- headers: {'x-token': token}
- }, (error, response) => {
- if (error || response.statusCode !== 200) {
- return reject(new Error(response.status));
- }
- return resolve(response.body);
- });
+ xhr({
+ method: 'DELETE',
+ uri: `${host}/${username}/${id}`,
+ headers: { 'x-token': token }
+ }, (error, response) => {
+ if (error || response.statusCode !== 200) {
+ return reject(new Error(response.status));
+ }
+ return resolve(response.body);
+ });
});
// Two types of backpack items are not retreivable through storage
// code, as json and sprite3 as arraybuffer zips.
const fetchAs = (responseType, uri) => new Promise((resolve, reject) => {
- xhr({uri, responseType}, (error, response) => {
- if (error || response.statusCode !== 200) {
- return reject(new Error(response.status));
- }
- return resolve(response.body);
- });
+ xhr({ uri, responseType }, (error, response) => {
+ if (error || response.statusCode !== 200) {
+ return reject(new Error(response.status));
+ }
+ return resolve(response.body);
+ });
});
// These two helpers allow easy fetching of backpack code and sprite zips
@@ -90,13 +92,13 @@ const fetchCode = fetchAs.bind(null, 'json');
const fetchSprite = fetchAs.bind(null, 'arraybuffer');
export {
- getBackpackContents,
- saveBackpackObject,
- deleteBackpackObject,
- costumePayload,
- soundPayload,
- spritePayload,
- codePayload,
- fetchCode,
- fetchSprite
+ getBackpackContents,
+ saveBackpackObject,
+ deleteBackpackObject,
+ costumePayload,
+ soundPayload,
+ spritePayload,
+ codePayload,
+ fetchCode,
+ fetchSprite
};
diff --git a/src/lib/default-project/index.js b/src/lib/default-project/index.js
index d6c80ddd9e1..75fac5d6717 100644
--- a/src/lib/default-project/index.js
+++ b/src/lib/default-project/index.js
@@ -9,46 +9,77 @@ import costume2 from '!raw-loader!./0fb9be3e8397c983338cb71dc84d0b25.svg?';
/* eslint-enable import/no-unresolved */
const defaultProject = translator => {
- let _TextEncoder;
- if (typeof TextEncoder === 'undefined') {
- _TextEncoder = require('fastestsmallesttextencoderdecoder').TextEncoder;
- } else {
- _TextEncoder = TextEncoder;
- }
- const encoder = new _TextEncoder();
+ let _TextEncoder;
+ if (typeof TextEncoder === 'undefined') {
+ _TextEncoder = require('fastestsmallesttextencoderdecoder').TextEncoder;
+ } else {
+ _TextEncoder = TextEncoder;
+ }
+ const encoder = new _TextEncoder();
- const projectJson = projectData(translator);
- return [{
- id: 0,
- assetType: 'Project',
- dataFormat: 'JSON',
- data: JSON.stringify(projectJson)
- }, {
- id: '83a9787d4cb6f3b7632b4ddfebf74367',
- assetType: 'Sound',
- dataFormat: 'WAV',
- data: new Uint8Array(popWav)
- }, {
- id: '83c36d806dc92327b9e7049a565c6bff',
- assetType: 'Sound',
- dataFormat: 'WAV',
- data: new Uint8Array(meowWav)
- }, {
- id: 'cd21514d0531fdffb22204e0ec5ed84a',
- assetType: 'ImageVector',
- dataFormat: 'SVG',
- data: encoder.encode(backdrop)
- }, {
- id: 'bcf454acf82e4504149f7ffe07081dbc',
- assetType: 'ImageVector',
- dataFormat: 'SVG',
- data: encoder.encode(costume1)
- }, {
- id: '0fb9be3e8397c983338cb71dc84d0b25',
- assetType: 'ImageVector',
- dataFormat: 'SVG',
- data: encoder.encode(costume2)
- }];
+ // const projectJson = {
+ // "targets": [
+ // {
+ // "isStage": true,
+ // "name": "Stage",
+ // "variables": [],
+ // "lists": [],
+ // "broadcasts": [],
+ // "costumes": [],
+ // "sounds": [],
+ // "draggable": false,
+ // "x": 0,
+ // "y": 0,
+ // "size": 100,
+ // "direction": 90,
+ // "layerOrder": 0,
+ // "currentCostume": 0,
+ // "currentSound": 0,
+ // "volume": 100,
+ // "tempo": 60,
+ // "blocks": [],
+ // "comments": [],
+ // "threads": [],
+ // "glow": false
+ // }
+ // ]
+ // };
+
+
+ const projectJson = projectData(translator);
+ console.log("TESTING");
+ console.log(JSON.stringify(projectJson));
+ return [{
+ id: 0,
+ assetType: 'Project',
+ dataFormat: 'JSON',
+ data: JSON.stringify(projectJson)
+ }, {
+ id: '83a9787d4cb6f3b7632b4ddfebf74367',
+ assetType: 'Sound',
+ dataFormat: 'WAV',
+ data: new Uint8Array(popWav)
+ }, {
+ id: '83c36d806dc92327b9e7049a565c6bff',
+ assetType: 'Sound',
+ dataFormat: 'WAV',
+ data: new Uint8Array(meowWav)
+ }, {
+ id: 'cd21514d0531fdffb22204e0ec5ed84a',
+ assetType: 'ImageVector',
+ dataFormat: 'SVG',
+ data: encoder.encode(backdrop)
+ }, {
+ id: 'bcf454acf82e4504149f7ffe07081dbc',
+ assetType: 'ImageVector',
+ dataFormat: 'SVG',
+ data: encoder.encode(costume1)
+ }, {
+ id: '0fb9be3e8397c983338cb71dc84d0b25',
+ assetType: 'ImageVector',
+ dataFormat: 'SVG',
+ data: encoder.encode(costume2)
+ }];
};
export default defaultProject;
diff --git a/src/lib/default-project/project-data.js b/src/lib/default-project/project-data.js
index 9ee63b237b5..640919465f7 100644
--- a/src/lib/default-project/project-data.js
+++ b/src/lib/default-project/project-data.js
@@ -1,20 +1,20 @@
-import {defineMessages} from 'react-intl';
+import { defineMessages } from 'react-intl';
import sharedMessages from '../shared-messages';
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'
- }
+ 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};
+messages = { ...messages, ...sharedMessages };
// use the default message if a translation function is not passed
const defaultTranslator = msgObj => msgObj.defaultMessage;
@@ -25,100 +25,174 @@ const defaultTranslator = msgObj => msgObj.defaultMessage;
* @return {object} the project data json for the default project
*/
const projectData = translateFunction => {
- const translator = translateFunction || defaultTranslator;
- return ({
- targets: [
- {
- isStage: true,
- name: 'Stage',
- variables: {
- '`jEk@4|i[#Fk?(8x)AV.-my variable': [
- translator(messages.variable),
- 0
- ]
- },
- lists: {},
- broadcasts: {},
- blocks: {},
- currentCostume: 0,
- costumes: [
- {
- assetId: 'cd21514d0531fdffb22204e0ec5ed84a',
- name: translator(messages.backdrop, {index: 1}),
- md5ext: 'cd21514d0531fdffb22204e0ec5ed84a.svg',
- dataFormat: 'svg',
- rotationCenterX: 240,
- rotationCenterY: 180
- }
- ],
- sounds: [
- {
- assetId: '83a9787d4cb6f3b7632b4ddfebf74367',
- name: translator(messages.pop),
- dataFormat: 'wav',
- format: '',
- rate: 11025,
- sampleCount: 258,
- md5ext: '83a9787d4cb6f3b7632b4ddfebf74367.wav'
- }
- ],
- volume: 100
- },
- {
- isStage: false,
- name: translator(messages.sprite, {index: 1}),
- variables: {},
- lists: {},
- broadcasts: {},
- blocks: {},
- currentCostume: 0,
- costumes: [
- {
- assetId: 'bcf454acf82e4504149f7ffe07081dbc',
- name: translator(messages.costume, {index: 1}),
- bitmapResolution: 1,
- md5ext: 'bcf454acf82e4504149f7ffe07081dbc.svg',
- dataFormat: 'svg',
- rotationCenterX: 48,
- rotationCenterY: 50
- },
- {
- assetId: '0fb9be3e8397c983338cb71dc84d0b25',
- name: translator(messages.costume, {index: 2}),
- bitmapResolution: 1,
- md5ext: '0fb9be3e8397c983338cb71dc84d0b25.svg',
- dataFormat: 'svg',
- rotationCenterX: 46,
- rotationCenterY: 53
- }
- ],
- sounds: [
- {
- assetId: '83c36d806dc92327b9e7049a565c6bff',
- name: translator(messages.meow),
- dataFormat: 'wav',
- format: '',
- rate: 22050,
- sampleCount: 18688,
- md5ext: '83c36d806dc92327b9e7049a565c6bff.wav'
- }
- ],
- volume: 100,
- visible: true,
- x: 0,
- y: 0,
- size: 100,
- direction: 90,
- draggable: false,
- rotationStyle: 'all around'
- }
+ const translator = translateFunction || defaultTranslator;
+ return ({
+ targets: [
+ {
+ isStage: true,
+ name: 'Stage',
+ variables: {
+ '`jEk@4|i[#Fk?(8x)AV.-my variable': [
+ translator(messages.variable),
+ 0
+ ]
+ },
+ lists: {},
+ broadcasts: {},
+ blocks: {
+
+ },
+ currentCostume: 0,
+ costumes: [
+ {
+ assetId: 'cd21514d0531fdffb22204e0ec5ed84a',
+ name: translator(messages.backdrop, { index: 1 }),
+ md5ext: 'cd21514d0531fdffb22204e0ec5ed84a.svg',
+ dataFormat: 'svg',
+ rotationCenterX: 240,
+ rotationCenterY: 180
+ }
+ ],
+ sounds: [
+ {
+ assetId: '83a9787d4cb6f3b7632b4ddfebf74367',
+ name: translator(messages.pop),
+ dataFormat: 'wav',
+ format: '',
+ rate: 11025,
+ sampleCount: 258,
+ md5ext: '83a9787d4cb6f3b7632b4ddfebf74367.wav'
+ }
],
- meta: {
- semver: '3.0.0',
- vm: '0.1.0',
- agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36' // eslint-disable-line max-len
- }
- });
+ volume: 100
+ },
+ {
+ isStage: false,
+ name: translator(messages.sprite, { index: 1 }),
+ variables: {},
+ lists: {},
+ broadcasts: {},
+ blocks: {},
+
+ // "0uLn5uNtj`ki1_5z+(Ba": {
+ // "opcode": "motion_movesteps",
+ // "next": null,
+ // "parent": "$)k)Sps+=$QVkZ?%mYJz",
+ // "inputs": {
+ // "STEPS": [
+ // 1,
+ // [
+ // 4,
+ // "-10"
+ // ]
+ // ]
+ // },
+ // "fields": {},
+ // "shadow": false,
+ // "topLevel": false
+ // },
+ // "$)k)Sps+=$QVkZ?%mYJz": {
+ // "opcode": "event_whenkeypressed",
+ // "next": "0uLn5uNtj`ki1_5z+(Ba",
+ // "parent": null,
+ // "inputs": {},
+ // "fields": {
+ // "KEY_OPTION": [
+ // "left arrow",
+ // null
+ // ]
+ // },
+ // "shadow": false,
+ // "topLevel": true,
+ // "x": 89,
+ // "y": 489
+ // },
+ // "@-EZS$Z6997_]0sE~9ye": {
+ // "opcode": "event_whenkeypressed",
+ // "next": "Pd)LrM7N=8c~p^hrMXtb",
+ // "parent": null,
+ // "inputs": {},
+ // "fields": {
+ // "KEY_OPTION": [
+ // "right arrow",
+ // null
+ // ]
+ // },
+ // "shadow": false,
+ // "topLevel": true,
+ // "x": 126,
+ // "y": 308
+ // },
+ // "Pd)LrM7N=8c~p^hrMXtb": {
+ // "opcode": "motion_movesteps",
+ // "next": null,
+ // "parent": "@-EZS$Z6997_]0sE~9ye",
+ // "inputs": {
+ // "STEPS": [
+ // 1,
+ // [
+ // 4,
+ // "10"
+ // ]
+ // ]
+ // },
+ // "fields": {},
+ // "shadow": false,
+ // "topLevel": false
+ // }
+
+ currentCostume: 0,
+ costumes: [
+ {
+ assetId: 'bcf454acf82e4504149f7ffe07081dbc',
+ name: translator(messages.costume, { index: 1 }),
+ bitmapResolution: 1,
+ md5ext: 'bcf454acf82e4504149f7ffe07081dbc.svg',
+ dataFormat: 'svg',
+ rotationCenterX: 48,
+ rotationCenterY: 50
+ },
+ {
+ assetId: '0fb9be3e8397c983338cb71dc84d0b25',
+ name: translator(messages.costume, { index: 2 }),
+ bitmapResolution: 1,
+ md5ext: '0fb9be3e8397c983338cb71dc84d0b25.svg',
+ dataFormat: 'svg',
+ rotationCenterX: 46,
+ rotationCenterY: 53
+ }
+ ],
+ scripts: [
+ "0uLn5uNtj`ki1_5z+(Ba",
+ "$)k)Sps+=$QVkZ?%mYJz"
+ ],
+ sounds: [
+ {
+ assetId: '83c36d806dc92327b9e7049a565c6bff',
+ name: translator(messages.meow),
+ dataFormat: 'wav',
+ format: '',
+ rate: 22050,
+ sampleCount: 18688,
+ md5ext: '83c36d806dc92327b9e7049a565c6bff.wav'
+ }
+ ],
+ volume: 100,
+ visible: true,
+ x: 0,
+ y: 0,
+ size: 100,
+ direction: 90,
+ draggable: false,
+ rotationStyle: 'all around'
+ }
+ ],
+ meta: {
+ semver: '3.0.0',
+ vm: '0.1.0',
+ agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36' // eslint-disable-line max-len
+ }
+ });
};
diff --git a/src/playground/index.ejs b/src/playground/index.ejs
index abbd5d8b024..9846e37ccbb 100644
--- a/src/playground/index.ejs
+++ b/src/playground/index.ejs
@@ -1,27 +1,43 @@
-
- <% if (htmlWebpackPlugin.options.gtm_id) { %>
+
+
+ <% if (htmlWebpackPlugin.options.gtm_id) { %>
-
<% } %>
-
-
-
-
- <%= htmlWebpackPlugin.options.title %>
-
-
- <% if (htmlWebpackPlugin.options.gtm_id) { %>
-
-
-
+
+
+
+
+
+ <%= htmlWebpackPlugin.options.title %>
+
+
+
+
+
+
+
+
+
+ <% if (htmlWebpackPlugin.options.gtm_id) { %>
+
+
+
<% } %>
-
+
+
diff --git a/webpack.config.js b/webpack.config.js
index 0ec57fa85e7..4e31aa172bd 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -10,157 +10,164 @@ const ScratchWebpackConfigBuilder = require('scratch-webpack-configuration');
// const STATIC_PATH = process.env.STATIC_PATH || '/static';
const commonHtmlWebpackPluginOptions = {
- // Google Tag Manager ID
- // Looks like 'GTM-XXXXXXX'
- gtm_id: process.env.GTM_ID || '',
+ // Google Tag Manager ID
+ // Looks like 'GTM-XXXXXXX'
+ gtm_id: process.env.GTM_ID || '',
- // Google Tag Manager env & auth info for alterative GTM environments
- // Looks like '>m_auth=0123456789abcdefghijklm>m_preview=env-00>m_cookies_win=x'
- // Taken from the middle of: GTM -> Admin -> Environments -> (environment) -> Get Snippet
- // Blank for production
- gtm_env_auth: process.env.GTM_ENV_AUTH || ''
+ // Google Tag Manager env & auth info for alterative GTM environments
+ // Looks like '>m_auth=0123456789abcdefghijklm>m_preview=env-00>m_cookies_win=x'
+ // Taken from the middle of: GTM -> Admin -> Environments -> (environment) -> Get Snippet
+ // Blank for production
+ gtm_env_auth: process.env.GTM_ENV_AUTH || ''
};
const baseConfig = new ScratchWebpackConfigBuilder(
- {
- rootPath: path.resolve(__dirname),
- enableReact: true,
- shouldSplitChunks: false,
- publicPath: 'auto'
- })
- .setTarget('browserslist')
- .merge({
- output: {
- assetModuleFilename: 'static/assets/[name].[hash][ext][query]',
- library: {
- name: 'GUI',
- type: 'umd2'
- }
- },
- resolve: {
- fallback: {
- Buffer: require.resolve('buffer/'),
- stream: require.resolve('stream-browserify')
- }
- }
- })
- .addModuleRule({
- test: /\.(svg|png|wav|mp3|gif|jpg)$/,
- resourceQuery: /^$/, // reject any query string
- type: 'asset' // let webpack decide on the best type of asset
- })
- .addPlugin(new webpack.DefinePlugin({
- 'process.env.DEBUG': Boolean(process.env.DEBUG),
- 'process.env.GA_ID': `"${process.env.GA_ID || 'UA-000000-01'}"`,
- 'process.env.GTM_ENV_AUTH': `"${process.env.GTM_ENV_AUTH || ''}"`,
- 'process.env.GTM_ID': process.env.GTM_ID ? `"${process.env.GTM_ID}"` : null
- }))
- .addPlugin(new CopyWebpackPlugin({
- patterns: [
- {
- from: 'node_modules/scratch-blocks/media',
- to: 'static/blocks-media/default'
- },
- {
- from: 'node_modules/scratch-blocks/media',
- to: 'static/blocks-media/high-contrast'
- },
- {
- // overwrite some of the default block media with high-contrast versions
- // this entry must come after copying scratch-blocks/media into the high-contrast directory
- from: 'src/lib/themes/high-contrast/blocks-media',
- to: 'static/blocks-media/high-contrast',
- force: true
- },
- {
- context: 'node_modules/scratch-vm/dist/web',
- from: 'extension-worker.{js,js.map}',
- noErrorOnMissing: true
- }
- ]
- }));
+ {
+ rootPath: path.resolve(__dirname),
+ enableReact: true,
+ shouldSplitChunks: false,
+ publicPath: 'auto'
+ })
+ .setTarget('browserslist')
+ .merge({
+ output: {
+ assetModuleFilename: 'static/assets/[name].[hash][ext][query]',
+ library: {
+ name: 'GUI',
+ type: 'umd2'
+ }
+ },
+ resolve: {
+ fallback: {
+ Buffer: require.resolve('buffer/'),
+ stream: require.resolve('stream-browserify')
+ }
+ }
+ })
+ .addModuleRule({
+ test: /\.(svg|png|wav|mp3|gif|jpg)$/,
+ resourceQuery: /^$/, // reject any query string
+ type: 'asset' // let webpack decide on the best type of asset
+ })
+ .addPlugin(new webpack.DefinePlugin({
+ 'process.env.DEBUG': Boolean(process.env.DEBUG),
+ 'process.env.GA_ID': `"${process.env.GA_ID || 'UA-000000-01'}"`,
+ 'process.env.GTM_ENV_AUTH': `"${process.env.GTM_ENV_AUTH || ''}"`,
+ 'process.env.GTM_ID': process.env.GTM_ID ? `"${process.env.GTM_ID}"` : null
+ }))
+ .addPlugin(new CopyWebpackPlugin({
+ patterns: [
+ {
+ from: 'node_modules/scratch-blocks/media',
+ to: 'static/blocks-media/default'
+ },
+ {
+ from: 'node_modules/scratch-blocks/media',
+ to: 'static/blocks-media/high-contrast'
+ },
+ {
+ // overwrite some of the default block media with high-contrast versions
+ // this entry must come after copying scratch-blocks/media into the high-contrast directory
+ from: 'src/lib/themes/high-contrast/blocks-media',
+ to: 'static/blocks-media/high-contrast',
+ force: true
+ },
+ {
+ context: 'node_modules/scratch-vm/dist/web',
+ from: 'extension-worker.{js,js.map}',
+ noErrorOnMissing: true
+ }
+ ]
+ }));
if (!process.env.CI) {
- baseConfig.addPlugin(new webpack.ProgressPlugin());
+ baseConfig.addPlugin(new webpack.ProgressPlugin());
}
// build the shipping library in `dist/`
const distConfig = baseConfig.clone()
- .merge({
- entry: {
- 'scratch-gui': path.join(__dirname, 'src/index.js')
- },
- output: {
- path: path.resolve(__dirname, 'dist')
+ .merge({
+ entry: {
+ 'scratch-gui': path.join(__dirname, 'src/index.js')
+ },
+ output: {
+ path: path.resolve(__dirname, 'dist')
+ }
+ })
+ .addExternals(['react', 'react-dom'])
+ .addPlugin(
+ new CopyWebpackPlugin({
+ patterns: [
+ {
+ from: 'src/lib/libraries/*.json',
+ to: 'libraries',
+ flatten: true
}
+ ]
})
- .addExternals(['react', 'react-dom'])
- .addPlugin(
- new CopyWebpackPlugin({
- patterns: [
- {
- from: 'src/lib/libraries/*.json',
- to: 'libraries',
- flatten: true
- }
- ]
- })
- );
+ );
// build the examples and debugging tools in `build/`
const buildConfig = baseConfig.clone()
- .enableDevServer(process.env.PORT || 8601)
- .merge({
- entry: {
- gui: './src/playground/index.jsx',
- blocksonly: './src/playground/blocks-only.jsx',
- compatibilitytesting: './src/playground/compatibility-testing.jsx',
- player: './src/playground/player.jsx'
- },
- output: {
- path: path.resolve(__dirname, 'build')
- }
- })
- .addPlugin(new HtmlWebpackPlugin({
- ...commonHtmlWebpackPluginOptions,
- chunks: ['gui'],
- template: 'src/playground/index.ejs',
- title: 'Scratch 3.0 GUI'
- }))
- .addPlugin(new HtmlWebpackPlugin({
- ...commonHtmlWebpackPluginOptions,
- chunks: ['blocksonly'],
- filename: 'blocks-only.html',
- template: 'src/playground/index.ejs',
- title: 'Scratch 3.0 GUI: Blocks Only Example'
- }))
- .addPlugin(new HtmlWebpackPlugin({
- ...commonHtmlWebpackPluginOptions,
- chunks: ['compatibilitytesting'],
- filename: 'compatibility-testing.html',
- template: 'src/playground/index.ejs',
- title: 'Scratch 3.0 GUI: Compatibility Testing'
- }))
- .addPlugin(new HtmlWebpackPlugin({
- ...commonHtmlWebpackPluginOptions,
- chunks: ['player'],
- filename: 'player.html',
- template: 'src/playground/index.ejs',
- title: 'Scratch 3.0 GUI: Player Example'
- }))
- .addPlugin(new CopyWebpackPlugin({
- patterns: [
- {
- from: 'static',
- to: 'static'
- },
- {
- from: 'extensions/**',
- to: 'static',
- context: 'src/examples'
- }
- ]
- }));
+ .enableDevServer(process.env.PORT || 8601, {
+ headers: {
+ 'Cross-Origin-Embedder-Policy': 'require-corp',
+ 'Cross-Origin-Opener-Policy': 'same-origin',
+ 'Cross-Origin-Resource-Policy': 'cross-origin',
+ 'Access-Control-Allow-Origin': '*' // Ensure proper CORS handling
+ }
+ })
+ .merge({
+ entry: {
+ gui: './src/playground/index.jsx',
+ blocksonly: './src/playground/blocks-only.jsx',
+ compatibilitytesting: './src/playground/compatibility-testing.jsx',
+ player: './src/playground/player.jsx'
+ },
+ output: {
+ path: path.resolve(__dirname, 'build')
+ }
+ })
+ .addPlugin(new HtmlWebpackPlugin({
+ ...commonHtmlWebpackPluginOptions,
+ chunks: ['gui'],
+ template: 'src/playground/index.ejs',
+ title: 'Scratch 3.0 GUI'
+ }))
+ .addPlugin(new HtmlWebpackPlugin({
+ ...commonHtmlWebpackPluginOptions,
+ chunks: ['blocksonly'],
+ filename: 'blocks-only.html',
+ template: 'src/playground/index.ejs',
+ title: 'Scratch 3.0 GUI: Blocks Only Example'
+ }))
+ .addPlugin(new HtmlWebpackPlugin({
+ ...commonHtmlWebpackPluginOptions,
+ chunks: ['compatibilitytesting'],
+ filename: 'compatibility-testing.html',
+ template: 'src/playground/index.ejs',
+ title: 'Scratch 3.0 GUI: Compatibility Testing'
+ }))
+ .addPlugin(new HtmlWebpackPlugin({
+ ...commonHtmlWebpackPluginOptions,
+ chunks: ['player'],
+ filename: 'player.html',
+ template: 'src/playground/index.ejs',
+ title: 'Scratch 3.0 GUI: Player Example'
+ }))
+ .addPlugin(new CopyWebpackPlugin({
+ patterns: [
+ {
+ from: 'static',
+ to: 'static'
+ },
+ {
+ from: 'extensions/**',
+ to: 'static',
+ context: 'src/examples'
+ }
+ ]
+ }));
// Skip building `dist/` unless explicitly requested
// It roughly doubles build time and isn't needed for `scratch-gui` development
@@ -169,5 +176,5 @@ const buildConfig = baseConfig.clone()
const buildDist = process.env.NODE_ENV === 'production' || process.env.BUILD_MODE === 'dist';
module.exports = buildDist ?
- [buildConfig.get(), distConfig.get()] :
- buildConfig.get();
+ [buildConfig.get(), distConfig.get()] :
+ buildConfig.get();