Scratch-guiのデフォルトプロジェクトを置き換える方法


※ 当ページには【広告/PR】を含む場合があります。
2020/08/20

Scratch3.0の開発者向けのソースコードプロジェクト
scratch-guiは一般に公開されているので、誰でも最新版の機能が実装できます。

特に独自定義したブロックを作成したい場合には、scratch-guiの内部のソースコードを弄って、目的のライブラリを追加しなければならない仕様です。

どちらかというと今回はプログラミング教育アプリの開発者向けのお話をしてみます。


合同会社タコスキングダム|タコキンのPスクール【Pschool厳選】Scratchを学べるオンライン・駅前プログラミングスクール5選

前置き

以前、弊社の別事業用の技術ブログNodejs x Alpine x DockerでScratch3.0の独自Extensions(拡張機能)を作成する開発環境を整えるにて、scratch-guiを利用するための環境を立ち上げる内容を特集していました。

このオフライン版のScratch3.0でも十分な機能が使えるのですが、初回にページをアクセスした場合のプロジェクトは必ず空のプロジェクト(ブロックキャンバスが空 + 1つの猫のスプライト...下の図参照)から始まります。

合同会社タコスキングダム|タコキンのPスクール

通常、自分のプログラム作品(完成品)を公開したい場合には、scratch公式サイト
https://scratch.mit.eduで自分のアカウントから公開できます。

そこからさらに一歩進んだ方法として、
scratch-guiでビルドしたウェブページをgithub.ioなどの静的なwebサイトのホスティングサービスによっても公開することも可能です。

スクラッチアプリをウェブサイト(SPA)として折角公開するのに、アクセスしたときにデフォルトページのままだと面白くもないはずです。

ですので、今回はカスタマイズしたスタートページから公開できる方法を以降で解説したいと思います。


合同会社タコスキングダム|タコキンのPスクール【Pschool厳選】Scratchをしっかり学ぶためのオススメ書籍まとめ

スクラッチのプロジェクトファイルの構造

デフォルトページを変更する上で、スクラッチのプロジェクトファイルであるsb3を理解する必要があります。

例えば、なにかスクラッチのプロジェクトを開いていただいて、
[ファイル] --> [コンピューターに保存]を選択し、sb3ファイルをどこかに保存しておきます。

合同会社タコスキングダム|タコキンのPスクール

さきにネタばれをすると、
sb3ファイルとは、zip形式のファイルです。

実際に拡張子を
.sb3から.zipに変更して、解凍ソフトなどでファイルを解凍すると、

合同会社タコスキングダム|タコキンのPスクール

このように、
project.jsonという定義ファイルに、svg(画像ファイル)とwav(音源)がパッケージされたものだと分かります。


合同会社タコスキングダム|タコキンのPスクール【Pschool厳選】Scratchを学べるオンライン・駅前プログラミングスクール5選

デフォルトプロジェクトの置き換え

それではプロジェクトの中身が分かったので、scratch-guiのデフォルトプロジェクトを、任意のプロジェクトで置き換える方法を解説します。

まず
scratch-guiのプロジェクトフォルダの中で、scratch-gui/src/lib/default-projectという場所を覗いてみましょう。

            
            $ tree -s scratch-gui/src/lib/default-project
scratch-gui/src/lib/default-project
├── [        560]  83a9787d4cb6f3b7632b4ddfebf74367.wav
├── [      37420]  83c36d806dc92327b9e7049a565c6bff.wav
├── [       6081]  b7853f557e4426412e64bb3da6531a99.svg
├── [        202]  cd21514d0531fdffb22204e0ec5ed84a.svg
├── [       6058]  e6ddc55a6ddd9cc9d84fe0b4c21e016f.svg
├── [       1803]  index.js
└── [       4472]  project-data.js
        
すると、2つのjsファイルと、画像と音源のリソースファイルが入っています。

これがデフォルトプロジェクトの中身になっているので、独自のカスタマイズする場合には、この
default-projectフォルダごと適切に置き換える必要があります。

ここから
default-projectを書き換えていきますが、念の為に何かあった際にいつでも戻せるように、default-projectフォルダはどこかに別名でコピーしてバックアップを作っておいたほうが良いと思います。

jsファイル

まずindex.jsの中身を理解するところから初めます。

            
            import projectData from './project-data';

//フォルダ内のリソースをインポート
import popWav from '!arraybuffer-loader!./83a9787d4cb6f3b7632b4ddfebf74367.wav';
//...他のリソースは省略

const defaultProject = translator => {

    //...中略

    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)
        },
        //...他のリソースの定義
    ];
};

export default defaultProject;
        
index.jsは、同フォルダにある全てのsvgwavファイルをインポートし、プロジェクト定義(project.json)とリソース定義などを配列として硬め、defaultProjectメソッドによってその配列を送り出しているようです。

もう一方の
project-data.jsですが、

            
            import {defineMessages} from 'react-intl';

//...中略

/**
 * Generate a localized version of the default project
 * @param {function} translateFunction a function to use for translating the default names
 * @return {object} the project data json for the default project
 */
const projectData = translateFunction => {
    const translator = translateFunction || defaultTranslator;
    return ({
        targets: [
            //...中略
        ],
        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
        }
    });
};

export default projectData;
        
という内容のように、project.jsonの中身をprojectDataメソッドでindex.js側に送りだしているだけの補助的なjsファイルです。

つまりは
project.jsonが直接読み込めれば、project-data.jsは無くても構わないです。

ソースコードの修正

このdefault-projectフォルダを、先程ダウンロードしてzip解凍していたプロジェクトで置き換えてみます。

解凍してできたリソースの中身をすべて
default-projectに移し、index.js以外は使わないで削除します。

            
            $ tree -s scratch-gui/src/lib/default-project
scratch-gui/src/lib/default-project
├── [       4814]  82b56e044f6d767e09b507a69b95df41.svg
├── [        560]  83a9787d4cb6f3b7632b4ddfebf74367.wav
├── [      37420]  83c36d806dc92327b9e7049a565c6bff.wav
├── [       4711]  9e94f2ec05ea588f7e48ee12678d22cc.svg
├── [       4962]  be8925e53870dff438c923ca84f7fb51.svg
├── [        202]  cd21514d0531fdffb22204e0ec5ed84a.svg
├── [     317083]  d3344650f594bcecdf46aa4a9441badd.svg
├── [       2254]  index.js     #👈再利用
└── [       7630]  project.json
        
そこからindex.jsを以下のように大幅改造してみます。

            
            import * as projectJson from './project.json';

/* eslint-disable import/no-unresolved */
import wav1 from '!arraybuffer-loader!./83a9787d4cb6f3b7632b4ddfebf74367.wav';
import wav2 from '!arraybuffer-loader!./83c36d806dc92327b9e7049a565c6bff.wav';
import svg1 from '!raw-loader!./9e94f2ec05ea588f7e48ee12678d22cc.svg';
import svg2 from '!raw-loader!./82b56e044f6d767e09b507a69b95df41.svg';
import svg3 from '!raw-loader!./be8925e53870dff438c923ca84f7fb51.svg';
import svg4 from '!raw-loader!./cd21514d0531fdffb22204e0ec5ed84a.svg';
import svg5 from '!raw-loader!./d3344650f594bcecdf46aa4a9441badd.svg';
/* eslint-enable import/no-unresolved */

//wav
const wavDict = {
    '83a9787d4cb6f3b7632b4ddfebf74367': wav1,
    '83c36d806dc92327b9e7049a565c6bff': wav2
};

//svg
const svgDict = {
    '9e94f2ec05ea588f7e48ee12678d22cc': svg1,
    '82b56e044f6d767e09b507a69b95df41': svg2,
    'be8925e53870dff438c923ca84f7fb51': svg3,
    'cd21514d0531fdffb22204e0ec5ed84a': svg4,
    'd3344650f594bcecdf46aa4a9441badd': svg5
};

const jsonCompose = (rawJson) => {
    return {
        id: 0,
        assetType: 'Project',
        dataFormat: 'JSON',
        data: JSON.stringify(rawJson.default)
    }
};

const wavCompose = () => {
    const wavs = [];
    for (let key in wavDict) {
        const item = {
            id: key,
            assetType: 'Sound',
            dataFormat: 'WAV',
            data: new Uint8Array(wavDict[key])
        };
        wavs.push(item);
    }
    return wavs;
};

const svgCompose = () => {
    let _TextEncoder;
    if (typeof TextEncoder === 'undefined') {
        _TextEncoder = require('text-encoding').TextEncoder;
    } else {
        _TextEncoder = TextEncoder;
    }
    const encoder = new _TextEncoder();
    const svgs = [];
    for (let key in svgDict) {
        const item = {
            id: key,
            assetType: 'ImageVector',
            dataFormat: 'SVG',
            data: encoder.encode(svgDict[key])
        };
        svgs.push(item);
    }
    return svgs;
};

const defaultProject = (translator) => {
    const assetArr = [jsonCompose(projectJson)];
    assetArr.concat(wavCompose());
    assetArr.concat(svgCompose());
    return assetArr;
};

export default defaultProject;
        
今回、インポートしている画像と音源のリソースはフォルダに入れたファイルの名前と合わせてその都度修正する必要がありますのでご注意ください。

それではデフォルトプロジェクトが置き換わっているかローカルサーバーを起動して確認してみます。

            
            $ cd scratch-gui && yarn start
        
以下のように、お目当てプロジェクトで起動できたら完了です!

合同会社タコスキングダム|タコキンのPスクール


合同会社タコスキングダム|タコキンのPスクール【Pschool厳選】Scratchを学べるオンライン・駅前プログラミングスクール5選

まとめ

オフライン版のスクラッチでも、デフォルトプロジェクトを変更することが可能になりました。

今回のテクニックを使えば独自のウェブページでスクラッチプログラムを運用することができますので、是非とも活用してみてください。