これまで紹介した方法はScratch 3のコードを少し改造して独自のブロックを作ってみる方法でした。Scratch 3には、独自の機能を持たせたブロックを追加するきちんとした方法が用意されています。それがこれから紹介するScratch 3の「拡張機能」です。
Scratch 3を触ったことがある人は、いままで「ペン」の機能や「音声合成」の機能を使ったことがある人もいるかもしれませんが、これらの機能も「拡張機能」として用意されているのです。
この章では、すでにあるブロックを改造するのではなく、オリジナルの拡張機能をつくることによって独自のブロックを追加してみます。
まず最初にscratch-vmのコードを修正します。node_modules以下にあるscratch-vm以下、src/extensionsの下にscratch3_helloという新しいフォルダを追加し、その下にindex.jsという新しいファイルを作成します。

index.jsの内容は以下の通りです。「Hello」という独自の拡張機能の定義となります。
const ArgumentType = require('../../extension-support/argument-type');
const BlockType = require('../../extension-support/block-type');
const Cast = require('../../util/cast');
class Scratch3Hello {
constructor (runtime) {
this.runtime = runtime;
}
getInfo () {
return {
id: 'hello',
name: 'Hello',
blocks: [
{
opcode: 'alert', // <-- (1)
blockType: BlockType.COMMAND, // <-- (2)
text: 'alert [TEXT]', // <-- (3)
arguments: { // <-- (4)
TEXT: {
type: ArgumentType.STRING,
defaultValue: "hello"
}
}
}
],
menus: {
}
};
}
alert (args) { // <-- (5)
const text = Cast.toString(args.TEXT); // <-- (6)
alert(text); // <-- (7)
}
}
module.exports = Scratch3Hello;
getInfo()の中身がブロックの定義です。(2)のblockTypeで追加するブロックのタイプを定義しており、ここではCOMMANDという、クリックしたとき何らかの処理を実行するタイプのブロックを指定しています。
クリックしたとき実行する処理の関数名が(1)のopcodeで指定されており、これが(5)と対応しています。
(3)のtextでブロックに表示するテキストを指定しています。alertというテキストのあとに[TEXT]と続いており、これは中身を自由に変更できるTEXTという引数の入力欄を表しています。
(4)のargumentsが引数の定義で、TEXTという名前の引数がSTRING(文字列)タイプで、デフォルトの値がhelloであることを表しています。
(5)のalert(args)には、ブロックをクリックしたときに実行される処理の内容が書かれています。
(6)で引数の中身をtextという定数に渡しており、(7)のalert(text)で、textというメッセージをアラートダイアログで表示しています。
さて、次にsrc/extension-support/extension-manager.jsを編集して、先程追加したscratch3_helloを追加します。
const builtinExtensions = {
pen: () => require('../extensions/scratch3_pen'),
wedo2: () => require('../extensions/scratch3_wedo2'),
music: () => require('../extensions/scratch3_music'),
microbit: () => require('../extensions/scratch3_microbit'),
text2speech: () => require('../extensions/scratch3_text2speech'),
translate: () => require('../extensions/scratch3_translate'),
videoSensing: () => require('../extensions/scratch3_video_sensing'),
speech2text: () => require('../extensions/scratch3_speech2text'),
ev3: () => require('../extensions/scratch3_ev3'),
makeymakey: () => require('../extensions/scratch3_makeymakey'), // <-- 最後のカンマも追加
hello: () => require('../extensions/scratch3_hello') // <-- この一行を追加
// todo: only load this extension once we have a compatible way to load its
// Vernier module dependency.
// gdxfor: () => require('../extensions/scratch3_gdx_for')
};
次にscratch-guiのコードを修正し、Hello拡張機能を「拡張機能」のメニューに追加して選べるようにします。scratch-gui以下のsrc/lib/libraries/extensions/index.jsxの最後に以下を追加します。
{
name: 'Hello',
extensionId: 'hello',
// collaborator: 'Hello',
// iconURL: helloImage,
// insetIconURL: helloInsetImage,
// description: (
// <FormattedMessage
// defaultMessage="Hello"
// description="Hello"
// id="gui.extension.hello.description"
// />
// ),
// featured: true,
// disabled: false,
// internetConnectionRequired: true,
// bluetoothRequired: false,
// helpLink: ''
}
直前の閉じ中括弧のあとのカンマを付け忘れないようにします。

Scratch3を起動中の場合は、ファイルを保存すると、自動でScratch3のページがリロードされます。(もし自動でリロードされなければ手動でリロードしてください)
起動していない場合は、ターミナルより
npm start
を実行して、Scratch3を起動します。
画面左下のフォルダアイコンをクリックし、Hello拡張機能を選んでください。追加された「alert hello」のブロックをクリックすれば「hello」というメッセージでアラートダイアログが開くようになります。

gifアニメを見て分かる通り、追加した独自拡張機能はHelloというタイトルがついただけの味気ないものです。
もし、他の拡張機能同様に画像を拡張機能メニューに表示したい場合は、src/lib/libraries/extensionsフォルダに適当な画像をhello.png(サイズ600x372)[サンプル]とhello-small.png(サイズ80x80)[サンプル]という名前で置いたあと、src/lib/libraries/extensions/index.jsxに追加したコードのiconURLとinsetIconURL、featured部分のコメントアウトを外し、

冒頭import文が続いたあと、
export default [
の直前に、helloImageとhelloInsetImageをimportするコードを追加します。

オリジナルの画像とともにHello拡張機能をメニューに表示することができます。

Hello拡張機能を追加した完成版は https://scratch3.netlify.app/ にて公開しています。