Skip to content
forked from bocoup/sb-util

sb-util, a library that can query Scratch projects via *.sb3 and project.json files

Notifications You must be signed in to change notification settings

mzgoddard/sb-util

 
 

Repository files navigation

sb-util

Table of Contents


sb-util Proposal (RFC)

We, at Bocoup, propose sb-util, a JavaScript and CLI utility that allows developers to query a Scratch Project for collections of sprites, blocks, assets, and project metadata.

sb-util will accomplish this by consuming .sb3 files generated by Scratch. .sb3 files are used to save and load projects, and within an .sb3 file there is a project.json, which is the JSON representation of the entities within a Scratch project. sb-util will provide an API that allows developers to query the project.json for project information.

The resulting tool should be usable in test suites, scripts, and applications.

Javascript API Proposal

API methods that have been implmented are marked with implemented.

Loading a Scratch Project - implemented

sb-util exposes loading functions to asynchronously instantiate a ScratchProject object. These loading functions handle file I/O and HTTP request handling, decoupling that process from the ScratchProject object itself.


loadSb3(sb3File)

Parameter(s): sb3File. String representing local file location of an *.sb3 file or a URI to an *.sb3 file
Return: Promise. This Promise object will resolve to a ScratchProject

const sp = await loadSb3('foo.sb3');

loadProjectJson(projectJsonFile)

Parameter(s): projectJsonFile. String representing local file location of an project.json file or a URI to an project.json file
Return: Promise. This Promise object will resolve to a ScratchProject

const sp = await loadProjectJson('project.json');

loadCloudId(cloudId)

Parameter(s): cloudId. Number representing a Cloud ID in Scratch
Return: Promise. This Promise object will resolve to a ScratchProject

const sp = await loadCloudId(123456);

ScratchProject

ScratchProject(projectJSON) - implemented
A ScratchProject gets initialized by an object, represented by the project.json. The assetFetcher is an optional constructor argument that represents an object is responsible for retrieving asset buffers for an Asset object.

const { ScratchProject } - require('sb-util');

// Use the above loading methods or directly instantiate:
const sp = new ScratchProject(projectJson);

Methods

assets()
Return: AssetCollection representing all the assets of a project

let assets = sp.assets()

blocks() -- implemented
Return: BlockCollection representing all the blocks in the project. This BlockCollection can be further filtered to get specific blocks

let blocks = sp.blocks();

sprites(...args) - implemented
Return: SpriteCollection representing all sprites in the project. A selector syntax can be passed to this function to get sprites that meet the syntax criteria

let sprites = sp.sprites();

let stage = sp.sprites('[isStage=true]').pop();
let sprite1 = sp.sprites('[name="Cat"]').pop(); 

stage() - implemented
Return: Sprite a stage

let stage = sp.stage();

variables() Return: a list of Variable objects in the project

let vars = sp.variables();

SpriteCollection

A SpriteCollection represents an iterable collection of objects that represent Sprites. Array methods such as map(), filter(), and pop() are available.

Methods

first() - implemented
Return: the first element in the SpriteCollection, null if the collection is empty

prop(attribute) - implemented
Parameter: attribute string. Return: the value of the given attribute for the first element in the SpriteCollection, undefined if the prop does not exist, null if the SpriteCollection is empty

Attributes available to pass: name, isStage, variables, lists, broadcasts, blocks, comments, currentCostume, costumes, sounds, volume, layerOrder, temp, videoTransparency, videoState, textToSpeechLanguage, visible, x, y, size, direction, draggable, rotationStyle

query(selector) - implemented
Parameter(s): selector string in the CSS selector syntax style. Return: SpriteCollection

let stage = sp.sprites('[isStage=true]');
let sprite1 = sp.sprites('[name="Cat"]');

Possible selector syntax, in attribute selector style:

Sprite Attribute Selector Syntax
isStage [isStage={true or false}]
layerOrder [layerOrder={a number}]
draggable [draggable={true or false}]
rotationStyle [rotationStyle={"all around" or "left-right" or "don't rotate"}]

Sprite

A Sprite is a singleton of SpriteCollection, with additional methods that are specific to a single Sprite. A Sprite can be a stage or an individual sprite.

Methods

prop(attribute) - implemented
Parameter: attribute string. Return: any value for a given attribute

const currentCostume = sprite.prop('currentCostume');

Attributes available to pass: name, isStage, variables, lists, broadcasts, blocks, comments, currentCostume, costumes, sounds, volume, layerOrder, temp, videoTransparency, videoState, textToSpeechLanguage, visible, x, y, size, direction, draggable, rotationStyle

blocks() - implemented
Return: BlockCollection

const sprite = sp.sprites('[name="Cat"]');
const blocks = sprite.blocks();

assets()
Return: AssetCollection

const assets = sprite.assets();

position() - implemented
Return: the (X, Y) cooredinates of a Sprite in Object notation

const { x, y } = sprite.position();

broadcasts() - implemented
Return: a list of Objects representing a broadcast, which contains an id and a message

const broadcasts = sprite.broadcasts();

// A mapping example
Object.entries(broadcasts).map(([key, value]) => ({ messageId: key, message: value }));

lists() - implemented
Return: a list of Objects representing a list, which contains an id, name, and an Array of values

const lists = sprite.lists();

Object.entries(lists).map(([key, value]) => console.log({key, listName: value[0], values: value[1]}));

BlockCollection

A BlockCollection represents and iterable collection of objects that represent Blocks. Array methods such as map(), filter(), and pop() are available.

Methods

first() - implemented
Return: the first element in the BlockCollection, null if the collection is empty

query(selector) - partially implemented
Parameter(s): selector, a string with the convention similar to CSS selector syntax
Return: BlockCollection

This is a mapping of Block object attributes to selector syntax:

Block Attribute CSS-like Selector Syntax Status
opcode (Full set of opcodes) Type selector. blocks.query('event_whenflagclicked') or blocks.query('control_if_else') implemented
block type (Full set of block types) Class selector. blocks.query('.motion') or blocks.query('.sensing') implemented
block shape (Full set of block shapes) Pseudo class selector. blocks.query(':hat') or blocks.query(':reporter') not implemented

The selector syntax can be combined for more fine-grained filtering.

Get all motion reporter blocks

const motionReporterBlocks = blocks.query('.motion :reporter');

renderToText()
Return: a text representation of blocks that are connected. The output will be a consumable JSON format, which can be written to a file and also be converted to YAML

const sprite1Blocks = sp.sprites({name: 'Sprite1'}).blocks();
const blockTextRepresentation = sprite1Blocks.renderToText()

// Output
{
    "blockGroups" : [
        // First group of blocks
        {
            "output": [
                "event_whenflagclicked",
                {
                    "control_if_else" : {
                        "if": {
                            "condition" : {
                                "sensing_keypressed": {
                                    "sensing_keyoptions": "space"
                                }
                            }
                        },
                        "then": [
                            {
                                "data_changevariableby": {
                                    "variable": "my variable",
                                    "value": 10
                                }
                            },
                            {
                                "motion_gotoxy": {
                                    "X": "my variable",
                                    "Y": 10
                                }
                            }
                        ],
                        "else": [
                            {
                                "control_wait_until": {
                                    "sensing_keypressed": {
                                        "sensing_keyoptions": "space"
                                    }
                                }
                            }
                        ]
                    }
                }
            ]
        },
        // Second group of blocks
        {
            "output": { ... }
        }
    ]
}

Block

A Block is a singleton of BlockCollection. It has additional methods, specific to the data held by an individual block.

Methods

prop(attribute) - implemented
Parameter: attribute string. Return: any value for a given attribute

Attributes available to pass: opcode, next, parent, inputs, fields, shadow, topLevel

args(selector)
This method is similar to query. args returns the inputs or fields (depending on the query string) of a block using one of the strings defined below. Certain query strings can return an input or a field.

A sample of selector values for the args method is defined in this table:

Inputs Fields Both Input and Field
X, Y, DURATION, MESSAGE, SECS CONDITION, SUBSTACK, OPERAND, TIMES, CHANGE, FROM, VALUE, BROADCAST_INPUT, BACKDROP, VOLUME, NUM1, NUM2 EFFECT, BROADCAST_OPTION, VARIABLE, STOP_OPTION COSTUME, TOUCHINGOBJECTMENU, TO, SOUND_MENU
const condition = block.args('CONDITION');
const variable = block.args('VARIABLE');
const operand = block.args('OPERAND');

substacks()
Returns the substacks for the block as an list of Objects representing a substack. If a block is not capable of having a substack, the list will be empty.


AssetCollection

An AssetCollection represents an interable collection of objects that represent Assets, which are static files included in an *.sb3 file or somwhere the user designates, used for costumes and sounds.

Methods

query(selector)
Parameter(s): A string in the CSS selector style Return: AssetCollection

Possible selector syntax:

Asset Attribute Selector Syntax
name Attribute selector. assets.query('name="83a9787d4cb6f3b7632b4ddfebf74367.wav")
dataFormat Type Selector. assets.query('wav')

Asset

An Asset is a singleton of AssetCollection.

Methods

toBuffer() Return: Promise to the file buffer of this Asset

CLI Proposal

Coming soon


Development

sb-util is implemented in TypeScript and will be available as a JavaScript library on npm and as a CLI tool.

Install Dependencies

npm install

Build

npm run build

Run Tests

npm test

Linting Code

This project uses https://prettier.io to format code and https://eslint.org/ for linting (catching errors). To format and lint, run

npm run lint

About

sb-util, a library that can query Scratch projects via *.sb3 and project.json files

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 99.8%
  • JavaScript 0.2%