├── .devcontainer └── devcontainer.json ├── .gitignore ├── 0-setup.sh ├── 1-add-dependency.sh ├── 2-build.sh ├── 3-run-private.sh ├── 4-publish.sh ├── Dockerfile ├── INSTRUCTIONS.md ├── LICENSE ├── README.md ├── dependencies ├── package-lock.json └── package.json ├── docs ├── 00-github.png ├── 01-github-account.png ├── 02-github-username.png ├── 03-github-welcome.png ├── 04-github-ready.png ├── 10-template-repo.png ├── 11-new-repo.png ├── 12-repo-name.png ├── 13-ready-repo.png ├── 20-create-codespace.png ├── 21-setting-up.png ├── 22-ready-codespace.png ├── 30-setup.png ├── 31-setup-complete.png ├── 40-extension-template.png ├── 41-constructor.png ├── 42-getinfo.png ├── 43-firstblock.png ├── 50-build.png ├── 51-building.png ├── 52-run.png ├── 53-running.png ├── 54-open-in-browser.png ├── 55-extensions-button.png ├── 55-extensions-menu.png ├── 55-private-scratch.png ├── 56-testing.png ├── 57-stop-test.png ├── 58-extensions.png ├── 59-extensions-icons.png ├── 60-publish.png ├── 61-published.png ├── 62-live.png ├── 63-testing.png ├── 64-public-url.png ├── 70-stop.png ├── 80-npmjs.png ├── 81-add-dependency.png ├── 82-npm-install-complete.png ├── 83-constructor.png ├── 84-get-info.png ├── 85-firstblock.png ├── 86-build.png ├── 86-open.png ├── 86-private-test.png ├── 87-publish.png ├── 87-test.png └── 88-stop.png ├── patches ├── scratch-gui.patch └── scratch-vm.patch ├── your-extension-background.png ├── your-extension-icon.png └── your-scratch-extension └── index.js /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Scratch Extension development environment", 3 | "image": "dalelane/scratch-extension-devenv:202303182007", 4 | "features": { 5 | }, 6 | "forwardPorts": [ 8000 ] 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | patched 2 | scratch-vm 3 | scratch-gui 4 | -------------------------------------------------------------------------------- /0-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | echo "Verifying location of Scratch source is known" 5 | if [ -z "$SCRATCH_SRC_HOME" ]; then 6 | echo "Error: SCRATCH_SRC_HOME environment variable is not set." 7 | exit 1 8 | fi 9 | 10 | echo "Checking if Scratch source has already been customized" 11 | if [ -e $SCRATCH_SRC_HOME/patched ]; then 12 | exit 1 13 | fi 14 | 15 | echo "Getting the location of this script" 16 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 17 | echo $DIR 18 | 19 | echo "Adding extension to Scratch source" 20 | cd $SCRATCH_SRC_HOME/scratch-vm/src/extensions 21 | ln -s $DIR/your-scratch-extension your-scratch-extension 22 | 23 | echo "Patching Scratch source to enable extension" 24 | cd $SCRATCH_SRC_HOME/scratch-vm 25 | git apply $DIR/patches/scratch-vm.patch 26 | mv package.json $DIR/dependencies/package.json 27 | ln -s $DIR/dependencies/package.json . 28 | mv package-lock.json $DIR/dependencies/package-lock.json 29 | ln -s $DIR/dependencies/package-lock.json . 30 | cd $SCRATCH_SRC_HOME/scratch-gui 31 | git apply $DIR/patches/scratch-gui.patch 32 | 33 | echo "Copying in the Scratch extension files" 34 | mkdir -p src/lib/libraries/extensions/yourextension 35 | cd src/lib/libraries/extensions/yourextension 36 | ln -s $DIR/your-extension-background.png your-extension-background.png 37 | ln -s $DIR/your-extension-icon.png your-extension-icon.png 38 | 39 | echo "Marking the Scratch source as customized" 40 | touch $SCRATCH_SRC_HOME/patched -------------------------------------------------------------------------------- /1-add-dependency.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | MODULE=$1 5 | 6 | echo "Verifying location of Scratch source is known" 7 | if [ -z "$SCRATCH_SRC_HOME" ]; then 8 | echo "Error: SCRATCH_SRC_HOME environment variable is not set." 9 | exit 1 10 | fi 11 | 12 | echo "Checking that Scratch has been patched" 13 | if [ ! -f "$SCRATCH_SRC_HOME/patched" ]; then 14 | echo "Scratch has not yet been patched. Run ./0-setup.sh" 15 | exit 1 16 | fi 17 | 18 | echo "Adding new dependency" 19 | cd $SCRATCH_SRC_HOME/scratch-vm 20 | npm install --save $MODULE 21 | 22 | -------------------------------------------------------------------------------- /2-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | echo "Verifying location of Scratch source is known" 5 | if [ -z "$SCRATCH_SRC_HOME" ]; then 6 | echo "Error: SCRATCH_SRC_HOME environment variable is not set." 7 | exit 1 8 | fi 9 | 10 | echo "BUILDING SCRATCH VM ..." 11 | cd $SCRATCH_SRC_HOME/scratch-vm 12 | NODE_OPTIONS='--openssl-legacy-provider' ./node_modules/.bin/webpack --bail 13 | 14 | echo "BUILDING SCRATCH GUI ..." 15 | cd $SCRATCH_SRC_HOME/scratch-gui 16 | NODE_OPTIONS='--openssl-legacy-provider' ./node_modules/.bin/webpack --bail 17 | -------------------------------------------------------------------------------- /3-run-private.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | python3 -m http.server -d $SCRATCH_SRC_HOME/scratch-gui/build 4 | -------------------------------------------------------------------------------- /4-publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | echo "Verifying location of Scratch source is known" 5 | if [ -z "$SCRATCH_SRC_HOME" ]; then 6 | echo "Error: SCRATCH_SRC_HOME environment variable is not set." 7 | exit 1 8 | fi 9 | 10 | echo "Checking that Scratch has been patched" 11 | if [ ! -f "$SCRATCH_SRC_HOME/patched" ]; then 12 | echo "Scratch has not yet been patched. Run ./0-setup.sh" 13 | exit 1 14 | fi 15 | 16 | # allow this script to be run from other locations, despite the 17 | # relative file paths used in it 18 | if [[ $BASH_SOURCE = */* ]]; then 19 | cd -- "${BASH_SOURCE%/*}/" || exit 20 | fi 21 | 22 | echo "Commit any changes" 23 | git add your-scratch-extension 24 | git add dependencies 25 | git commit -m "Update" 26 | git push origin master 27 | 28 | echo "Building the Scratch fork" 29 | ./2-build.sh 30 | 31 | echo "Preparing a gh-pages branch" 32 | DEVBRANCH=$(git rev-parse --abbrev-ref HEAD) 33 | if git rev-parse --verify gh-pages >/dev/null 2>&1 34 | then 35 | git checkout gh-pages 36 | else 37 | git checkout -b gh-pages 38 | fi 39 | 40 | echo "Preparing a publish folder" 41 | if [ -d "scratch" ] 42 | then 43 | rm -rf ./scratch/* 44 | else 45 | mkdir scratch 46 | fi 47 | 48 | echo "Publishing the Scratch fork" 49 | cp -rf $SCRATCH_SRC_HOME/scratch-gui/build/* ./scratch/. 50 | git add scratch 51 | git commit -m "Update" 52 | git push origin gh-pages 53 | 54 | echo "Returning to dev branch" 55 | git checkout $DEVBRANCH 56 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/javascript-node:0-18-bullseye 2 | 3 | # setup the location of the Scratch code 4 | WORKDIR /usr/app 5 | RUN chown node:node /usr/app 6 | 7 | # switch to the Scratch developer user account 8 | USER node 9 | 10 | # get the base Scratch code 11 | RUN git clone --depth=1 https://github.com/LLK/scratch-vm.git 12 | RUN git clone --depth=1 https://github.com/LLK/scratch-gui.git 13 | 14 | # build Scratch vm 15 | WORKDIR /usr/app/scratch-vm 16 | RUN npm install 17 | RUN npm ln 18 | 19 | # build Scratch gui 20 | WORKDIR /usr/app/scratch-gui 21 | RUN npm install 22 | RUN npm ln scratch-vm 23 | 24 | # location of the Scratch source code 25 | ENV SCRATCH_SRC_HOME=/usr/app 26 | 27 | # copy extension development files 28 | WORKDIR /usr/app 29 | COPY 2-build.sh . 30 | COPY 3-run-private.sh . 31 | 32 | # initial default build 33 | RUN ./2-build.sh 34 | -------------------------------------------------------------------------------- /INSTRUCTIONS.md: -------------------------------------------------------------------------------- 1 | # Develop your own Scratch extension 2 | 3 | - **Create your account** 4 | - [Create an account on GitHub](#create-an-account-on-github) 5 | - **Setup your development environment** 6 | - [Create your Scratch repository](#create-your-scratch-development-repository) 7 | - [Go into Codespaces](#launch-codespaces) 8 | - [Set up repository](#set-up-your-repository) 9 | - **Create your extension** 10 | - [Create a block using live data from an online API](#create-a-block-using-live-data) 11 | - [Create a block using a JavaScript module from npm](#create-a-block-using-a-javascript-module) 12 | - [Customize the Extension Menu](#customize-the-extensions-menu) 13 | - **Publish your extension** 14 | - [Publish your Scratch extension](#publish-your-finished-extension) 15 | - [Stop your codespace](#stop-your-codespace) 16 | 17 | --- 18 | 19 | ## Create an account on GitHub 20 | 21 | _**If you already have a GitHub account, you can [skip to the next step](#create-your-scratch-development-repository).**_ 22 | 23 | Go to https://github.com 24 | 25 | ![screenshot](./docs/00-github.png) 26 | 27 | Click on **Sign up** 28 | 29 | ![screenshot](./docs/01-github-account.png) 30 | 31 | Create your account 32 | 33 | ![screenshot](./docs/02-github-username.png) 34 | 35 | Note that your GitHub **username** will be part of the web address for your modified Scratch fork, so you may want to keep that in mind when you choose your username. 36 | 37 | ![screenshot](./docs/03-github-welcome.png) 38 | 39 | When you get to the **Welcome** screen, you can fill in the personalization survey if you wish, but it is okay to click on the **Skip personalization** link at the bottom of the screen if you prefer. 40 | 41 | ![screenshot](./docs/04-github-ready.png) 42 | 43 | You should now have a GitHub account, ready to create your Scratch repository. 44 | 45 | --- 46 | 47 | ## Create your Scratch development repository 48 | 49 | Go to https://github.com/dalelane/scratch-extension-development 50 | 51 | _If you aren't already logged into GitHub, you should log in now._ 52 | 53 | ![screenshot](./docs/10-template-repo.png) 54 | 55 | Click on **Use this template** and then choose **Create a new repository** 56 | 57 | ![screenshot](./docs/11-new-repo.png) 58 | 59 | Give your new repository a name. 60 | 61 | Note that the repository name will be part of the web address for your modified Scratch fork, so you may want to keep that in mind when you choose a name. 62 | 63 | ![screenshot](./docs/12-repo-name.png) 64 | 65 | Your repository is ready for use. 66 | 67 | ![screenshot](./docs/13-ready-repo.png) 68 | 69 | --- 70 | 71 | ## Launch codespaces 72 | 73 | Click on **Code** -> **Codespaces** -> **Create codespace** 74 | 75 | ![screenshot](./docs/20-create-codespace.png) 76 | 77 | It can take a minute or two to set up your codespace. 78 | 79 | ![screenshot](./docs/21-setting-up.png) 80 | 81 | Your codespace is ready for use. 82 | 83 | ![screenshot](./docs/22-ready-codespace.png) 84 | 85 | --- 86 | 87 | ## Set up your repository 88 | 89 | In the terminal at the bottom of the window, run: 90 | ```sh 91 | ./0-setup.sh 92 | ``` 93 | 94 | ![screenshot](./docs/30-setup.png) 95 | 96 | This should be very quick. 97 | 98 | You only need to do this once (but it is safe if you run it again). 99 | 100 | ![screenshot](./docs/31-setup-complete.png) 101 | 102 | --- 103 | 104 | ## Create a block using live data 105 | 106 | **The instructions here will show you how to write an extension that can lookup the title of a book from the ISBN number, using an online API.** 107 | 108 | The instructions will go through the template JavaScript one section at a time. 109 | 110 | Open the `your-scratch-extension/index.js` file. 111 | 112 | Review the sample extension to see the sort of options that are available to you. 113 | 114 | ![screenshot](./docs/40-extension-template.png) 115 | 116 | Edit the `getInfo()` function to provide a description of your first block. 117 | 118 | ```js 119 | getInfo () { 120 | return { 121 | // unique ID for your extension 122 | id: 'yourScratchExtension', 123 | 124 | // name displayed in the Scratch UI 125 | name: 'Demo', 126 | 127 | // colours to use for your extension blocks 128 | color1: '#000099', 129 | color2: '#660066', 130 | 131 | // your Scratch blocks 132 | blocks: [ 133 | { 134 | // function where your code logic lives 135 | opcode: 'myFirstBlock', 136 | 137 | // type of block 138 | blockType: BlockType.REPORTER, 139 | 140 | // label to display on the block 141 | text: 'Title for ISBN book [BOOK_NUMBER]', 142 | 143 | // arguments used in the block 144 | arguments: { 145 | BOOK_NUMBER: { 146 | defaultValue: 1718500564, 147 | 148 | // type/shape of the parameter 149 | type: ArgumentType.NUMBER 150 | } 151 | } 152 | } 153 | ] 154 | }; 155 | } 156 | ``` 157 | 158 | ![screenshot](docs/42-getinfo.png) 159 | 160 | Edit the `myFirstBlock` function implementation to look up book info using the [OpenLibrary API](https://openlibrary.org/dev/docs/api/books). 161 | 162 | ```js 163 | myFirstBlock ({ BOOK_NUMBER }) { 164 | return fetch('https://openlibrary.org/isbn/' + BOOK_NUMBER + '.json') 165 | .then((response) => { 166 | if (response.ok) { 167 | return response.json(); 168 | } 169 | else { 170 | return { title: 'Unknown' }; 171 | } 172 | }) 173 | .then((bookinfo) => { 174 | return bookinfo.title; 175 | }); 176 | } 177 | ``` 178 | 179 | ![screenshot](./docs/43-firstblock.png) 180 | 181 | Your code is now ready to test. 182 | 183 | --- 184 | 185 | ## Launch a private test of your Scratch extension 186 | 187 | In the terminal at the bottom of the window, run: 188 | ```sh 189 | ./2-build.sh 190 | ``` 191 | 192 | ![screenshot](./docs/50-build.png) 193 | 194 | This can take a minute to run. Wait for this to complete. 195 | 196 | In the terminal at the bottom of the window, run: 197 | ```sh 198 | ./3-run-private.sh 199 | ``` 200 | 201 | ![screenshot](./docs/52-run.png) 202 | 203 | A pop-up should appear in the bottom-right with a button to open a private window with your modified version of Scratch. 204 | 205 | ![screenshot](./docs/53-running.png) 206 | 207 | If it doesn't appear, or you accidentally dismiss it, you can get the link from the **Open in browser** button on the **Ports** tab. 208 | 209 | ![screenshot](./docs/54-open-in-browser.png) 210 | 211 | Either way, click on **Open in browser**. 212 | 213 | ![screenshot](./docs/55-private-scratch.png) 214 | 215 | This is a private copy of Scratch that only you can access. You can use this to test your new extension. 216 | 217 | Click on the **Extensions** button. 218 | 219 | ![screenshot](./docs/55-extensions-button.png) 220 | 221 | You should see your extension added to the menu. Click on it. 222 | 223 | ![screenshot](./docs/55-extensions-menu.png) 224 | 225 | Make a simple Scratch project using your extension. 226 | 227 | ![screenshot](./docs/56-testing.png) 228 | 229 | If you need to make a change, stop your Scratch test by pressing **Control-C** in the terminal. 230 | 231 | Make your code changes. 232 | 233 | Then re-build and test again by typing: 234 | ```sh 235 | ./2-build.sh 236 | ./3-run-private.sh 237 | ``` 238 | 239 | Once you have finished, stop your Scratch test by pressing **Control-C** in the terminal. 240 | 241 | ![screenshot](./docs/57-stop-test.png) 242 | 243 | --- 244 | 245 | ## Create a block using a JavaScript module 246 | 247 | **The instructions here will show you how to write an extension that can estimate the number of syllables in some English text, using a JavaScript module.** 248 | 249 | The instructions will go through the template JavaScript one section at a time. 250 | 251 | Select a module from https://www.npmjs.com - for this example, I'm using `syllable`. 252 | 253 | ![screenshot](./docs/80-npmjs.png) 254 | 255 | Run `./1-add-dependency.sh` with the name of the module you've selected. 256 | ```sh 257 | ./1-add-dependency.sh syllable 258 | ``` 259 | 260 | ![screenshot](./docs/81-add-dependency.png) 261 | 262 | As long as you have spelled it exactly correctly, it will update the dependencies for your private Scratch build to include the new module. 263 | 264 | _If you want to add multiple dependencies, you can run this script multiple times. Running the script with the name of a dependency you have already added is safe, but not necessary._ 265 | 266 | ![screenshot](./docs/82-npm-install-complete.png) 267 | 268 | Open the `your-scratch-extension/index.js` file again. 269 | 270 | Edit the `constructor` function to load the module. 271 | ```js 272 | constructor (runtime) { 273 | import('syllable') 274 | .then((syllableModule) => { 275 | this.syllable = syllableModule.syllable; 276 | }); 277 | } 278 | ``` 279 | 280 | ![screenshot](./docs/83-constructor.png) 281 | 282 | Edit the `getInfo()` function to add a second block, after the block we defined before. 283 | 284 | The complete `getInfo()` function will now contain: 285 | 286 | ```js 287 | getInfo () { 288 | return { 289 | // unique ID for your extension 290 | id: 'yourScratchExtension', 291 | 292 | // name displayed in the Scratch UI 293 | name: 'Demo', 294 | 295 | // colours to use for your extension blocks 296 | color1: '#000099', 297 | color2: '#660066', 298 | 299 | // your Scratch blocks 300 | blocks: [ 301 | { 302 | // function where your code logic lives 303 | opcode: 'myFirstBlock', 304 | 305 | // type of block 306 | blockType: BlockType.REPORTER, 307 | 308 | // label to display on the block 309 | text: 'Title for ISBN book [BOOK_NUMBER]', 310 | 311 | // arguments used in the block 312 | arguments: { 313 | BOOK_NUMBER: { 314 | defaultValue: 1718500564, 315 | 316 | // type/shape of the parameter 317 | type: ArgumentType.NUMBER 318 | } 319 | } 320 | }, 321 | { 322 | // function where your code logic lives 323 | opcode: 'mySecondBlock', 324 | 325 | // type of block 326 | blockType: BlockType.REPORTER, 327 | 328 | // label to display on the block 329 | text: 'Syllables in [MY_TEXT]', 330 | 331 | // arguments used in the block 332 | arguments: { 333 | MY_TEXT: { 334 | defaultValue: 'Hello World', 335 | 336 | // type/shape of the parameter 337 | type: ArgumentType.STRING 338 | } 339 | } 340 | } 341 | ] 342 | }; 343 | } 344 | ``` 345 | 346 | ![screenshot](./docs/84-get-info.png) 347 | 348 | Add a `mySecondBlock` function implementation to return a count of syllables using the loaded npm module. 349 | 350 | ```js 351 | mySecondBlock ({ MY_TEXT }) { 352 | return this.syllable(MY_TEXT); 353 | } 354 | ``` 355 | 356 | ![screenshot](./docs/85-firstblock.png) 357 | 358 | 359 | Your code is now ready to test. 360 | 361 | As before, build your code: 362 | 363 | ```sh 364 | ./2-build.sh 365 | ``` 366 | 367 | ![screenshot](./docs/86-build.png) 368 | 369 | Then run a private instance of Scratch to test it. 370 | 371 | ```sh 372 | ./3-run-private.sh 373 | ``` 374 | 375 | ![screenshot](./docs/86-private-test.png) 376 | 377 | When prompted, click on the **Open in browser** button to open your private Scratch instance. 378 | 379 | ![screenshot](./docs/86-open.png) 380 | 381 | You can make a simple Scratch script to verify that your new block is working. 382 | 383 | ![screenshot](./docs/87-test.png) 384 | 385 | When you've finished your test, close the Scratch window, and then stop the test instance by pressing **Control-C** in the Terminal. 386 | 387 | ![screenshot](./docs/88-stop.png) 388 | 389 | --- 390 | 391 | ## Customize the Extensions menu 392 | 393 | The extensions menu includes images to represent each extension. Each extension has a large background image, and a small inset icon. 394 | 395 | Placeholder images are provided for your extension. 396 | 397 | ![screenshot](./docs/58-extensions.png) 398 | 399 | If you're happy with these, you can [skip to the next step](#publish-your-finished-extension). 400 | 401 | If you want to customize these, you can edit the image files `your-extension-background.png` and `your-extension-icon.png` to better represent your Scratch extension. 402 | 403 | ![screenshot](./docs/59-extensions-icons.png) 404 | 405 | I recommend keeping the dimensions of the images the same as they currently are to best fit in the menu. 406 | 407 | Note that you will need to rebuild your extension after making changes to these files. 408 | 409 | ```sh 410 | ./2-build.sh 411 | ``` 412 | 413 | And to see the new menu in action you will want to start your private test instance again. 414 | 415 | ```sh 416 | ./3-run-private.sh 417 | ``` 418 | 419 | Before proceeding to the next step, make sure you have stopped your private test instance of Scratch by pressing **Control-C** in the terminal. 420 | 421 | ![screenshot](./docs/57-stop-test.png) 422 | 423 | --- 424 | 425 | ## Publish your finished extension 426 | 427 | In the terminal at the bottom of the window, run: 428 | ```sh 429 | ./4-publish.sh 430 | ``` 431 | 432 | ![screenshot](./docs/60-publish.png) 433 | 434 | This can take a minute to run. 435 | 436 | ![screenshot](./docs/61-published.png) 437 | 438 | Your Scratch fork will be live and publicly accessible at: 439 | 440 | ``` 441 | https://.github.io//scratch 442 | ``` 443 | 444 | For example, in my screenshots I created a GitHub account with the username `scratch-extensions-demo` and when I forked the repository, I named it `my-demo`. 445 | 446 | ![screenshot](./docs/64-public-url.png) 447 | 448 | _Note that this can sometimes take a minute to go live, so if the link doesn't work, it's worth waiting a minute and trying again. (But if it still doesn't work, check you have got the URL correct!)_ 449 | 450 | ![screenshot](./docs/62-live.png) 451 | 452 | You can give this URL to your students. 453 | 454 | ![screenshot](./docs/63-testing.png) 455 | 456 | --- 457 | 458 | ## Stop your codespace 459 | 460 | You only need your codespace running while you are developing your extension. Once it's published, you must stop your codespace. 461 | 462 | On your repository page, click on **Code** -> **Codespaces** -> **Stop codespace**. 463 | 464 | ![screenshot](./docs/70-stop.png) 465 | 466 | Your published Scratch instance, with your extensions, will still be accessible after you do this. 467 | 468 | ![screenshot](./docs/63-testing.png) 469 | 470 | --- 471 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Development environment for creating unofficial Scratch extensions 2 | 3 | This is a repo for [my workshop](https://www.eventbrite.co.uk/e/workshop-write-your-own-scratch-extension-tickets-533502218497) at the [Raspberry Pi Clubs Conference](https://www.raspberrypi.org/clubs-conference-2023/) - about how to create your own custom blocks for Scratch. 4 | 5 | This repo has [instructions](./INSTRUCTIONS.md), a template extension, and an online hosted development environment, so you can create your own Scratch extensions using only a web browser. No local developmnent tools or other software is needed. 6 | 7 | I've included step-by-step instructions for building different types of Scratch extensions, including Scratch blocks based on web APIs, and Scratch blocks based on JavaScript modules from npm. 8 | 9 | I created it for educators and coding group volunteers, who would like to customize Scratch for their students by giving them new and unique blocks to create with. In particular, I wanted to make this accessible to people who perhaps don't necessarily think of themselves as developers and wouldn't otherwise know how to clone the Scratch Team repos and start hacking it. 10 | 11 | Go to [INSTRUCTIONS.md](./INSTRUCTIONS.md) to find a written step-by-step guide, or watch me step through the process in [this video](https://youtu.be/bX9ZqhuxtnI). 12 | 13 | [![screenshot](./docs/63-testing.png)](https://youtu.be/bX9ZqhuxtnI) 14 | 15 | I've wrapped all the complicated bits in scripts that set everything up, and prepared an online Scratch extension development environment – so everything can be done in a web browser without having to install or configure anything on your own computer. 16 | 17 | If you make something with this, please [let me know](https://github.com/dalelane/scratch-extension-development/issues) - I'd love to hear about it. 18 | 19 | -------------------------------------------------------------------------------- /dependencies/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scratch-vm", 3 | "version": "1.3.69", 4 | "description": "Virtual Machine for Scratch 3.0", 5 | "author": "Massachusetts Institute of Technology", 6 | "license": "BSD-3-Clause", 7 | "homepage": "https://github.com/LLK/scratch-vm#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/LLK/scratch-vm.git", 11 | "sha": "d54f07ce7fc9b20276f9c776dfb32ec4b482bcc2" 12 | }, 13 | "main": "./dist/node/scratch-vm.js", 14 | "browser": "./src/index.js", 15 | "scripts": { 16 | "build": "npm run docs && webpack --progress --colors --bail", 17 | "coverage": "tap ./test/{unit,integration}/*.js --coverage --coverage-report=lcov", 18 | "deploy": "touch playground/.nojekyll && gh-pages -t -d playground -m \"Build for $(git log -n1 --pretty=format:\"%h %s\") [skip ci]\"", 19 | "docs": "jsdoc -c .jsdoc.json", 20 | "i18n:src": "mkdirp translations/core && format-message extract --out-file translations/core/en.json src/extensions/**/index.js", 21 | "i18n:push": "tx-push-src scratch-editor extensions translations/core/en.json", 22 | "lint": "eslint . && format-message lint src/**/*.js", 23 | "prepare": "husky install", 24 | "prepublish": "in-publish && npm run build || not-in-publish", 25 | "start": "webpack-dev-server", 26 | "tap": "tap ./test/{unit,integration}/*.js", 27 | "tap:unit": "tap ./test/unit/*.js", 28 | "tap:integration": "tap ./test/integration/*.js", 29 | "test": "npm run lint && npm run tap", 30 | "watch": "webpack --progress --colors --watch", 31 | "version": "json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"" 32 | }, 33 | "config": { 34 | "commitizen": { 35 | "path": "cz-conventional-changelog" 36 | } 37 | }, 38 | "tap": { 39 | "branches": 60, 40 | "functions": 70, 41 | "lines": 70, 42 | "statements": 70 43 | }, 44 | "dependencies": { 45 | "@vernier/godirect": "1.5.0", 46 | "arraybuffer-loader": "^1.0.6", 47 | "atob": "2.1.2", 48 | "btoa": "1.2.1", 49 | "canvas-toBlob": "1.0.0", 50 | "decode-html": "2.0.0", 51 | "diff-match-patch": "1.0.4", 52 | "format-message": "6.2.1", 53 | "htmlparser2": "3.10.0", 54 | "immutable": "3.8.1", 55 | "jszip": "^3.1.5", 56 | "minilog": "3.1.0", 57 | "scratch-parser": "5.1.1", 58 | "scratch-sb1-converter": "0.2.7", 59 | "scratch-translate-extension-languages": "0.0.20191118205314", 60 | "text-encoding": "0.7.0", 61 | "worker-loader": "^1.1.1" 62 | }, 63 | "peerDependencies": { 64 | "scratch-svg-renderer": "^0.2.0-prerelease" 65 | }, 66 | "devDependencies": { 67 | "@babel/core": "7.13.10", 68 | "@babel/preset-env": "7.14.8", 69 | "@commitlint/cli": "17.0.2", 70 | "@commitlint/config-conventional": "17.0.2", 71 | "adm-zip": "0.4.11", 72 | "babel-eslint": "10.1.0", 73 | "babel-loader": "8.2.2", 74 | "callsite": "1.0.0", 75 | "copy-webpack-plugin": "4.5.4", 76 | "docdash": "1.2.0", 77 | "eslint": "5.3.0", 78 | "eslint-config-scratch": "5.1.0", 79 | "expose-loader": "0.7.5", 80 | "file-loader": "2.0.0", 81 | "format-message-cli": "6.2.0", 82 | "gh-pages": "1.2.0", 83 | "husky": "8.0.1", 84 | "in-publish": "2.0.1", 85 | "js-md5": "0.7.3", 86 | "jsdoc": "3.6.6", 87 | "json": "^9.0.4", 88 | "lodash.defaultsdeep": "4.6.1", 89 | "pngjs": "3.3.3", 90 | "scratch-audio": "0.1.0-prerelease.20221123180128", 91 | "scratch-blocks": "0.1.0-prerelease.20230302080617", 92 | "scratch-l10n": "3.15.20230302032139", 93 | "scratch-render": "0.1.0-prerelease.20230221152523", 94 | "scratch-render-fonts": "1.0.0-prerelease.20221102164332", 95 | "scratch-semantic-release-config": "1.0.5", 96 | "scratch-storage": "2.0.2", 97 | "scratch-svg-renderer": "0.2.0-prerelease.20210727023023", 98 | "script-loader": "0.7.2", 99 | "semantic-release": "19.0.5", 100 | "stats.js": "0.17.0", 101 | "tap": "16.2.0", 102 | "tiny-worker": "2.3.0", 103 | "uglifyjs-webpack-plugin": "1.2.7", 104 | "webpack": "4.46.0", 105 | "webpack-cli": "3.1.0", 106 | "webpack-dev-server": "3.11.2" 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /docs/00-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/00-github.png -------------------------------------------------------------------------------- /docs/01-github-account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/01-github-account.png -------------------------------------------------------------------------------- /docs/02-github-username.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/02-github-username.png -------------------------------------------------------------------------------- /docs/03-github-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/03-github-welcome.png -------------------------------------------------------------------------------- /docs/04-github-ready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/04-github-ready.png -------------------------------------------------------------------------------- /docs/10-template-repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/10-template-repo.png -------------------------------------------------------------------------------- /docs/11-new-repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/11-new-repo.png -------------------------------------------------------------------------------- /docs/12-repo-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/12-repo-name.png -------------------------------------------------------------------------------- /docs/13-ready-repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/13-ready-repo.png -------------------------------------------------------------------------------- /docs/20-create-codespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/20-create-codespace.png -------------------------------------------------------------------------------- /docs/21-setting-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/21-setting-up.png -------------------------------------------------------------------------------- /docs/22-ready-codespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/22-ready-codespace.png -------------------------------------------------------------------------------- /docs/30-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/30-setup.png -------------------------------------------------------------------------------- /docs/31-setup-complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/31-setup-complete.png -------------------------------------------------------------------------------- /docs/40-extension-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/40-extension-template.png -------------------------------------------------------------------------------- /docs/41-constructor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/41-constructor.png -------------------------------------------------------------------------------- /docs/42-getinfo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/42-getinfo.png -------------------------------------------------------------------------------- /docs/43-firstblock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/43-firstblock.png -------------------------------------------------------------------------------- /docs/50-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/50-build.png -------------------------------------------------------------------------------- /docs/51-building.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/51-building.png -------------------------------------------------------------------------------- /docs/52-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/52-run.png -------------------------------------------------------------------------------- /docs/53-running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/53-running.png -------------------------------------------------------------------------------- /docs/54-open-in-browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/54-open-in-browser.png -------------------------------------------------------------------------------- /docs/55-extensions-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/55-extensions-button.png -------------------------------------------------------------------------------- /docs/55-extensions-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/55-extensions-menu.png -------------------------------------------------------------------------------- /docs/55-private-scratch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/55-private-scratch.png -------------------------------------------------------------------------------- /docs/56-testing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/56-testing.png -------------------------------------------------------------------------------- /docs/57-stop-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/57-stop-test.png -------------------------------------------------------------------------------- /docs/58-extensions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/58-extensions.png -------------------------------------------------------------------------------- /docs/59-extensions-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/59-extensions-icons.png -------------------------------------------------------------------------------- /docs/60-publish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/60-publish.png -------------------------------------------------------------------------------- /docs/61-published.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/61-published.png -------------------------------------------------------------------------------- /docs/62-live.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/62-live.png -------------------------------------------------------------------------------- /docs/63-testing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/63-testing.png -------------------------------------------------------------------------------- /docs/64-public-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/64-public-url.png -------------------------------------------------------------------------------- /docs/70-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/70-stop.png -------------------------------------------------------------------------------- /docs/80-npmjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/80-npmjs.png -------------------------------------------------------------------------------- /docs/81-add-dependency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/81-add-dependency.png -------------------------------------------------------------------------------- /docs/82-npm-install-complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/82-npm-install-complete.png -------------------------------------------------------------------------------- /docs/83-constructor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/83-constructor.png -------------------------------------------------------------------------------- /docs/84-get-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/84-get-info.png -------------------------------------------------------------------------------- /docs/85-firstblock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/85-firstblock.png -------------------------------------------------------------------------------- /docs/86-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/86-build.png -------------------------------------------------------------------------------- /docs/86-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/86-open.png -------------------------------------------------------------------------------- /docs/86-private-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/86-private-test.png -------------------------------------------------------------------------------- /docs/87-publish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/87-publish.png -------------------------------------------------------------------------------- /docs/87-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/87-test.png -------------------------------------------------------------------------------- /docs/88-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/docs/88-stop.png -------------------------------------------------------------------------------- /patches/scratch-gui.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/lib/libraries/extensions/index.jsx b/src/lib/libraries/extensions/index.jsx 2 | index ba18b91..e316f38 100644 3 | --- a/src/lib/libraries/extensions/index.jsx 4 | +++ b/src/lib/libraries/extensions/index.jsx 5 | @@ -1,6 +1,9 @@ 6 | import React from 'react'; 7 | import {FormattedMessage} from 'react-intl'; 8 | 9 | +import yourExtensionInsetIconURL from './yourextension/your-extension-icon.png'; 10 | +import yourExtensionIconURL from './yourextension/your-extension-background.png'; 11 | + 12 | import musicIconURL from './music/music.png'; 13 | import musicInsetIconURL from './music/music-small.svg'; 14 | 15 | @@ -47,6 +50,15 @@ import gdxforConnectionIconURL from './gdxfor/gdxfor-illustration.svg'; 16 | import gdxforConnectionSmallIconURL from './gdxfor/gdxfor-small.svg'; 17 | 18 | export default [ 19 | + { 20 | + name: 'Your Extension', 21 | + extensionId: 'yourScratchExtension', 22 | + iconURL: yourExtensionIconURL, 23 | + insetIconURL: yourExtensionInsetIconURL, 24 | + description: 'Your custom Scratch extension', 25 | + featured: true, 26 | + disabled: false 27 | + }, 28 | { 29 | name: ( 30 | require('../extensions/scratch3_ev3'), 7 | makeymakey: () => require('../extensions/scratch3_makeymakey'), 8 | boost: () => require('../extensions/scratch3_boost'), 9 | - gdxfor: () => require('../extensions/scratch3_gdx_for') 10 | + gdxfor: () => require('../extensions/scratch3_gdx_for'), 11 | + yourScratchExtension: () => require('../extensions/your-scratch-extension') 12 | }; 13 | 14 | /** 15 | diff --git a/webpack.config.js b/webpack.config.js 16 | index 6a8a3b3..ed3fa2b 100644 17 | --- a/webpack.config.js 18 | +++ b/webpack.config.js 19 | @@ -36,7 +36,10 @@ const base = { 20 | }) 21 | ] 22 | }, 23 | - plugins: [] 24 | + plugins: [], 25 | + resolve: { 26 | + symlinks: false 27 | + } 28 | }; 29 | 30 | module.exports = [ 31 | -------------------------------------------------------------------------------- /your-extension-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/your-extension-background.png -------------------------------------------------------------------------------- /your-extension-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalelane/scratch-extension-development/54be2d6e08acb1d8057c15e0d436e350e9296ac6/your-extension-icon.png -------------------------------------------------------------------------------- /your-scratch-extension/index.js: -------------------------------------------------------------------------------- 1 | const BlockType = require('../../extension-support/block-type'); 2 | const ArgumentType = require('../../extension-support/argument-type'); 3 | const TargetType = require('../../extension-support/target-type'); 4 | 5 | class Scratch3YourExtension { 6 | 7 | constructor (runtime) { 8 | // put any setup for your extension here 9 | } 10 | 11 | /** 12 | * Returns the metadata about your extension. 13 | */ 14 | getInfo () { 15 | return { 16 | // unique ID for your extension 17 | id: 'yourScratchExtension', 18 | 19 | // name that will be displayed in the Scratch UI 20 | name: 'Demo', 21 | 22 | // colours to use for your extension blocks 23 | color1: '#000099', 24 | color2: '#660066', 25 | 26 | // icons to display 27 | blockIconURI: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAFCAAAAACyOJm3AAAAFklEQVQYV2P4DwMMEMgAI/+DEUIMBgAEWB7i7uidhAAAAABJRU5ErkJggg==', 28 | menuIconURI: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAFCAAAAACyOJm3AAAAFklEQVQYV2P4DwMMEMgAI/+DEUIMBgAEWB7i7uidhAAAAABJRU5ErkJggg==', 29 | 30 | // your Scratch blocks 31 | blocks: [ 32 | { 33 | // name of the function where your block code lives 34 | opcode: 'myFirstBlock', 35 | 36 | // type of block - choose from: 37 | // BlockType.REPORTER - returns a value, like "direction" 38 | // BlockType.BOOLEAN - same as REPORTER but returns a true/false value 39 | // BlockType.COMMAND - a normal command block, like "move {} steps" 40 | // BlockType.HAT - starts a stack if its value changes from false to true ("edge triggered") 41 | blockType: BlockType.REPORTER, 42 | 43 | // label to display on the block 44 | text: 'My first block [MY_NUMBER] and [MY_STRING]', 45 | 46 | // true if this block should end a stack 47 | terminal: false, 48 | 49 | // where this block should be available for code - choose from: 50 | // TargetType.SPRITE - for code in sprites 51 | // TargetType.STAGE - for code on the stage / backdrop 52 | // remove one of these if this block doesn't apply to both 53 | filter: [ TargetType.SPRITE, TargetType.STAGE ], 54 | 55 | // arguments used in the block 56 | arguments: { 57 | MY_NUMBER: { 58 | // default value before the user sets something 59 | defaultValue: 123, 60 | 61 | // type/shape of the parameter - choose from: 62 | // ArgumentType.ANGLE - numeric value with an angle picker 63 | // ArgumentType.BOOLEAN - true/false value 64 | // ArgumentType.COLOR - numeric value with a colour picker 65 | // ArgumentType.NUMBER - numeric value 66 | // ArgumentType.STRING - text value 67 | // ArgumentType.NOTE - midi music value with a piano picker 68 | type: ArgumentType.NUMBER 69 | }, 70 | MY_STRING: { 71 | // default value before the user sets something 72 | defaultValue: 'hello', 73 | 74 | // type/shape of the parameter - choose from: 75 | // ArgumentType.ANGLE - numeric value with an angle picker 76 | // ArgumentType.BOOLEAN - true/false value 77 | // ArgumentType.COLOR - numeric value with a colour picker 78 | // ArgumentType.NUMBER - numeric value 79 | // ArgumentType.STRING - text value 80 | // ArgumentType.NOTE - midi music value with a piano picker 81 | type: ArgumentType.STRING 82 | } 83 | } 84 | } 85 | ] 86 | }; 87 | } 88 | 89 | 90 | /** 91 | * implementation of the block with the opcode that matches this name 92 | * this will be called when the block is used 93 | */ 94 | myFirstBlock ({ MY_NUMBER, MY_STRING }) { 95 | // example implementation to return a string 96 | return MY_STRING + ' : doubled would be ' + (MY_NUMBER * 2); 97 | } 98 | } 99 | 100 | module.exports = Scratch3YourExtension; 101 | --------------------------------------------------------------------------------