Skip to main content

開発者向けカスタム拡張機能

TurboWarpは、URLパラメータで指定される実験的なサンドボックス化された拡張機能をサポートしています(例:https://turbowarp.org/editor?extension=https://extensions.turbowarp.org/fetch.js)。拡張子を複数回設定することで、複数の拡張子を読み込むことができます。

warning

カスタム拡張機能を使用するプロジェクトは、ScratchのWebサイトにアップロードすることはできません。プロジェクトは、同じ拡張機能を持つTurboWarpインスタンスがURLから既にロードしている場合にのみロードできます。

カスタム拡張機能の書き方入門

info

このページは、あなたがすでにJavaScriptを理解していることを前提にしています。もしあなたがJavaScriptをまだ理解していないなら、このページを読んでも楽しい体験にはならないでしょう。

このページはまだ未完成です。GitHub で改善点を提案したり、書き込んだりすることは歓迎されますし、奨励されます。

warning

この文書にある拡張機能のURLの例は、実際のプロジェクトでは使用しないでください。また、将来にわたって動作する保証はありません。

カスタム拡張は サンドボックス の中で実行され、Scratchの内部へのアクセスは制限されます。これは非常に制限されたものですが、カスタム拡張は fetchWebSocket などの強力な Web API にアクセスすることができます。

サンドボックスの技術的な制限により、カスタム拡張機能を呼び出すたびに、ターボモードや画面更新なしの実行に関係なく、現在のスクリプトがフルフレームで停止します。

カスタム拡張機能は、GitHub Pages などのウェブサイトから読み込む必要があります。開発には、ローカルのHTTPサーバーをセットアップするのが最適でしょう。Pythonがインストールされていれば、python -m http.serverのように簡単に設定することができます。

Hello, world!

最もシンプルなカスタム拡張機能は、次のようなものです。

example.js
// We use class syntax to define our extension object
// This isn't actually necessary, but it tends to look the best

class MyExtension {
/**
* Scratch will call this method *once* when the extension loads.
* This method's job is to tell Scratch things like the extension's ID, name, and what blocks it supports.
*/
getInfo() {
return {
// `id` is the internal ID of the extension
// It should never change!
// If you choose to make an actual extension, please change this to something else.
// Only the characters a-z and 0-9 can be used. No spaces or special characters.
id: 'myextensionexample',

// `name` is what the user sees in the toolbox
// It can be changed without breaking projects.
name: 'Cool Extension',

blocks: [
{
// `opcode` is the internal ID of the block
// It should never change!
// It corresponds to the class method with the same name.
opcode: 'hello',
blockType: Scratch.BlockType.REPORTER,
text: 'Hello, world!'
}
]
};
}

/**
* Corresponds to `opcode: 'hello'` above
*/
hello() {
// You can just return a value: any string, boolean, or number will work.
// If you have to perform an asynchronous action like a request, just return a Promise.
// The block will wait until the Promise resolves and return the resolved value.
return 'Hello, world!';
}
}

// Call Scratch.extensions.register to register your extension
// Make sure to register each extension exactly once
Scratch.extensions.register(new MyExtension());

Test this example here. (Do not use this link to make real projects!)

これをコンピュータ上のファイルに保存し、ローカルのHTTPサーバでextensionパラメータを使って読み込む。もし、python -m http.serverでローカルのHTTPサーバーを起動していれば、 https://turbowarp.org/editor?extension=http://localhost:8000/example.js にアクセスできるかもしれません。この拡張機能は、"Hello, world!" を出力する単一のレポーターブロックを含む新しいカテゴリを追加します。

getInfo

getInfo は、Scratch にあなたの拡張機能やサポートしているブロックを伝える関数です。

  • id は、この拡張機能が使用するユニークな ID を表す文字列です。a-zと0-9の文字のみを含む必要があります。IDを変更すると既存のプロジェクトが壊れてしまうので、同じエクステンションは常に同じIDを使用する必要があります。
  • name は、Scratch にサイドバーに表示する名前を指定する文字列です。
  • blocks はオブジェクトのリストで、拡張機能がどのブロックを含んでいるかを定義します。
    • opcode はブロックの内部名であり、ブロックが実行されたときに呼び出されるメソッドに対応します。オペコードは決して変更してはいけません。
    • blockType はブロックの種類を定義します。
      • Scratch.BlockType.REPORTER は、ラウンドレポーターを作ります。
      • Scratch.BlockType.BOOLEAN は、ブーリアン入力にフィットする三角形のレポーターを作ります。
      • Scratch.BlockType.COMMAND でスタックブロックを作成します。
    • text はエディター上でブロックにどのような名前を付けるかを定義する文字列です。[brackets] のテキストは、引数用のスロットに変換されます(以下の例を参照してください)。
    • arguments は、ブロックが受け取る引数を定義するオブジェクトです。 各引数が持つ、
      • type は、作成する入力形状を定義するものです。ここで設定された型に関係なく、実際にブロックに渡される値が正しい型にキャストされることは保証されていないことに注意してください。例えば、引数は文字列として渡されることが多いので、手動で数値に変換する必要があります。
        • 文字列入力には Scratch.ArgumentType.STRING を、数値入力には Scratch.ArgumentType.NUMBER を使用します。
        • 数値入力用の Scratch.ArgumentType.NUMBER
        • ブーリアン入力用の Scratch.ArgumentType.BOOLEAN (defaultValue は無視されます)
        • 角度を表す Scratch.ArgumentType.ANGLE
        • 色を表す Scratch.ArgumentType.COLOR (#123abc 文字列フォーマット)
        • 5x5 の行列を表す Scratch.ArgumentType.MATRIX (111010101... string format で渡されます。)
        • 音符を表す Scratch.ArgumentType.NOTE
      • DefaultValue は、ライブラリからブロックを作成したときの初期値です。
    • disableMonitortrue に設定することで、モニターを作成するブロックのチェックボックスを強制的に外すことができます。

より複雑な例

あなたはおそらく、上記の言葉を理解できなかったでしょう。ここでは、引数を使ったより徹底的な例を紹介します。

strict-equality.js
class StrictEqualityExtension {
getInfo() {
return {
id: 'strictequalityexample', // change this if you make an actual extension!
name: 'Strict Equality',
blocks: [
{
opcode: 'strictlyEquals',
blockType: Scratch.BlockType.BOOLEAN,
text: '[ONE] strictly equals [TWO]',
arguments: {
ONE: {
type: Scratch.ArgumentType.STRING,
defaultValue: 'First value'
},
TWO: {
type: Scratch.ArgumentType.STRING,
defaultValue: 'Second value'
}
}
}
]
};
}
strictlyEquals(args) {
// Note strict equality: Inputs must match exactly: in type, case, etc.
return args.ONE === args.TWO;
}
}
Scratch.extensions.register(new StrictEqualityExtension());

Test this example here. (Do not use this link to make real projects!)

変更を適用するには、リロードする必要があることを忘れないでください。

デバッギング

何らかの理由で拡張機能が表示されない場合、またはページの読み込みが完了しない場合は、開発者コンソールを開いてエラーを検索してください。そこに何か書いてある可能性があります。

それはさておき、カスタムエクステンションは単なるJavaScriptスクリプトです。console.logdebugger は好きなだけ使ってください。

サンドボックス

カスタム拡張機能は、セキュリティ上の理由からアクセスできるものを制限するサンドボックスの中で実行されます。この「サンドボックス」は実際にはサンドボックス化された不可視の <iframe> (sandbox 属性を使用) と制限された機能ポリシーです。これは通常のScratchとは異なることに注意してください。

  • カスタム拡張機能で VM 内部へのアクセスができない
  • カスタム拡張機能では、引数として明示的に渡されなかった変数にアクセスすることはできません。
  • カスタム拡張機能はスプライトと直接対話することはできません。
  • カスタム拡張機能は、ほとんどの Web API にアクセスし、サーバーへの接続を開くことができます(CORS が許可する限り)。

下位互換性

拡張機能は、可能な限り後方互換性を保つように努力すべきです。特筆すべきは下記の通りです。

  • 拡張子IDは絶対に変更しないでください
  • 絶対にブロックを削除しない
  • 決してオペコードを変更しない
  • ブロックの挙動を大幅に変更しない
    • しかし、ブロックへの有効な呼び出しは、常に同じ動作をするようにしなければなりません。
  • 既存のプロジェクトで拡張機能を徹底的にテストする

これらのガイドラインに従わない場合、プロジェクトが事実上崩壊する可能性があります。

Scratchとの相違点

TurboWarpのカスタム拡張機能は、ScratchやE羊cquesのカスタム拡張機能と比較して、いくつかの顕著な変更点があります。

  • TurboWarpはサンドボックス化されたサードパーティの <iframe> でカスタム拡張機能を実行しますが、Scratchはファーストパーティの Worker を使用します。つまり、カスタム拡張は別のオリジンで実行されますが(たとえばturbowarp.orgのindexedDBにはアクセスできません)、ゲームパッドAPIなどのよりDOM APIにはアクセスできます。

その他のリソース