Skip to main content

Adding a Category

Adding the category to scratch-blocks

Let's move the alert block to a Dialogs category.

blocks_vertical

First, create a file called dialogs.js in blocks_vertical.

At the top of the file put:

scratch-blocks/blocks_vertical/dialogs.js
'use strict';

goog.provide('Blockly.Blocks.dialogs'); // "dialogs" being the category.

goog.require('Blockly.Blocks');
goog.require('Blockly.Colours');
goog.require('Blockly.ScratchBlocks.VerticalExtensions');

Move your block from looks.js to dialogs.js (leaving looks.js like it was originally).

scratch-blocks/blocks_vertical/dialogs.js
Blockly.Blocks['dialogs_alert'] = {
/**
* @this Blockly.Block
*/
init: function(){
this.jsonInit({
"message0": Blockly.Msg.DIALOGS_ALERT,
"args0": [
{
"type": "input_value",
"name": "MESSAGE"
}
],
"category": Blockly.Categories.dialogs,
"extensions": ["colours_dialogs", "shape_statement"]
});
}
};

The block messages

First, move your block's message to a new section (to keep the file organised) and update the message to match the one in the block definition.

Second, under the "Category labels" section, add one for your new category.

scratch-blocks/msg/messages.js
// Category labels
Blockly.Msg.CATEGORY_DIALOGS = 'Dialogs';
Blockly.Msg.CATEGORY_MOTION = 'Motion';
Blockly.Msg.CATEGORY_LOOKS = 'Looks';
Blockly.Msg.CATEGORY_SOUND = 'Sound';
Blockly.Msg.CATEGORY_EVENTS = 'Events';
Blockly.Msg.CATEGORY_CONTROL = 'Control';
Blockly.Msg.CATEGORY_SENSING = 'Sensing';
Blockly.Msg.CATEGORY_OPERATORS = 'Operators';
Blockly.Msg.CATEGORY_VARIABLES = 'Variables';
Blockly.Msg.CATEGORY_MYBLOCKS = 'My Blocks';

The block category

In core/constants.js, find Blockly.Categories and add your category to it.

scratch-blocks/core/constants.js
/**
* ENUM for categories.
* @const
*/
Blockly.Categories = {
"dialogs": "dialogs",
"motion": "motion",
"looks": "looks",
"sound": "sounds",
"pen": "pen",
"data": "data",
"dataLists": "data-lists",
"event": "events",
"control": "control",
"sensing": "sensing",
"operators": "operators",
"more": "more"
};

The block colour

In core/colours.js, add your colour to the Blockly.Colours object.

scratch-blocks/core/colours.js
// ...
goog.provide('Blockly.Colours');

Blockly.Colours = {
// SVG colours: these must be specificed in #RRGGBB style
// To add an opacity, this must be specified as a separate property (for SVG fill-opacity)
"dialogs": {
"primary": "#60a05c",
"secondary": "#4c8249",
"tertiary": "#31542f",
"quaternary": "#31542f"
},
"motion": {
"primary": "#4C97FF",
"secondary": "#4280D7",
"tertiary": "#3373CC",
"quaternary": "#3373CC"
},
// ...
};

The colours are these:

ColourHex CodeExample
Primary#60a05c
Secondary#4c8249
Tertiary#31542f
Quaternary#31542f

The block colour extension

In the blocks_vertical/vertical_extensions.js file, in the function Blockly.ScratchBlocks.VerticalExtensions.registerAll, add your category's name to the categoryNames variable.

scratch-blocks/blocks_vertical/vertical_extensions.js
/**
* Register all extensions for scratch-blocks.
* @package
*/
Blockly.ScratchBlocks.VerticalExtensions.registerAll = function() {
var categoryNames =
['control', 'data', 'data_lists', 'sounds', 'motion', 'looks', 'event',
'sensing', 'pen', 'operators', 'more', 'dialogs'];
// Register functions for all category colours.
for (var i = 0; i < categoryNames.length; i++) {
var name = categoryNames[i];
Blockly.Extensions.register('colours_' + name,
Blockly.ScratchBlocks.VerticalExtensions.colourHelper(name));
}

// ...
};

Adding the category to scratch-gui

Adding the category to the toolbox

In src/lib/make-toolbox-xml.js, remove your changes from the looks category and add the following:

scratch-gui/src/lib/make-toolbox-xml.js
/* eslint-disable no-unused-vars */
const dialogs = function (isInitialSetup, isStage, targetId, colors) {
const hello = ScratchBlocks.ScratchMsgs.translate('LOOKS_HELLO', 'Hello!');
// Note: the category's secondaryColour matches up with the blocks' tertiary color, both used for border color.
return `
<category name="%{BKY_CATEGORY_DIALOGS}" id="dialogs" colour="${colors.primary}" secondaryColour="${colors.tertiary}">
<block type="dialogs_alert">
<value name="MESSAGE">
<shadow type="text">
<field name="TEXT">${hello}</field>
</shadow>
</value>
</block>
${categorySeparator}
</category>
`;
};

At the bottom of the file, there is a function called makeToolboxXml, make the highlighted changes to it:

scratch-gui/src/lib/make-toolbox-xml.js
const makeToolboxXML = function (isInitialSetup, isStage = true, targetId, categoriesXML = [],
costumeName = '', backdropName = '', soundName = '', colors = defaultColors) {
// ...

categoriesXML = categoriesXML.slice();
const moveCategory = categoryId => {
// ...
};
const dialogsXML = moveCategory('dialogs') || dialogs(isInitialSetup, isStage, targetId, colors.dialogs);
const motionXML = moveCategory('motion') || motion(isInitialSetup, isStage, targetId, colors.motion);
const looksXML = moveCategory('looks') ||
looks(isInitialSetup, isStage, targetId, costumeName, backdropName, colors.looks);
// ...

const everything = [
xmlOpen,
dialogsXML, gap,
motionXML, gap,
looksXML, gap,
// ...
myBlocksXML
];

for (const extensionCategory of categoriesXML) {
everything.push(gap, extensionCategory.xml);
}

everything.push(xmlClose);
return everything.join('\n');
}

Adding the block to the default theme

In the file src/lib/themes/default/index.js, add the block colours you specified in scratch-blocks's core/colours.js

scratch-gui/src/lib/themes/default/index.js
const blockColors = {
dialogs: {
primary: "#60a05c",
secondary: "#4c8249",
tertiary: "#31542f",
quaternary: "#31542f"
},
// ...
};
tip

If you want, you can also add the category to the dark, high-constrast or your own custom themes themes.

Adding the category to scratch-vm.

First, remove the changes from scratch3_looks.js.

In the src/blocks folder, add a tutorialmod_dialogs.js file.

scratch-vm/src/blocks/tutorialmod_dialogs.js
class TutorialModDialogsBlocks {
constructor (runtime){
/**
* The runtime instantiating this block package.
* @type {Runtime}
*/
this.runtime = runtime;
}

/**
* Retrieve the block primitives implemented by this package.
* @return {object.<string, Function>} Mapping of opcode to Function.
*/
getPrimitives () {
return {
dialogs_alert: this.alertBlock
};
}

alertBlock(args, util) {
alert(args.MESSAGE);
}
}

module.exports = TutorialModDialogsBlocks;

And finally, in src/engine/runtime.js, add your category's file to defaultBlockPackages

scratch-vm/src/engine/runtime.js
const defaultBlockPackages = {
tutorialmod_dialogs: require('../blocks/tutorialmod_dialogs'),
scratch3_control: require('../blocks/scratch3_control'),
scratch3_event: require('../blocks/scratch3_event'),
scratch3_looks: require('../blocks/scratch3_looks'),
scratch3_motion: require('../blocks/scratch3_motion'),
scratch3_operators: require('../blocks/scratch3_operators'),
scratch3_sound: require('../blocks/scratch3_sound'),
scratch3_sensing: require('../blocks/scratch3_sensing'),
scratch3_data: require('../blocks/scratch3_data'),
scratch3_procedures: require('../blocks/scratch3_procedures')
};

Make scratch-vm understand how to load the category from save

In scratch-vm's src/serialization/sb3.js file, find the CORE_CATEGORIES array and add your category to it.

scratch-vm/src/serialization/sb3.js
const CORE_EXTENSIONS = [
'argument',
'colour',
'control',
'data',
'event',
'looks',
'math',
'motion',
'operator',
'procedures',
'sensing',
'sound',
'dialogs'
];

Completed Files

ComponentFileDownload
scratch-blocksblocks_vertical/dialogs.jsdialogs.js
scratch-blocksblocks_vertical/vertical_extensions.jsvertical_extensions.js
scratch-blockscore/colours.jscolours.js
scratch-blockscore/constants.jsconstants.js
scratch-blocksmsg/messages.jsmessages.js
scratch-guisrc/lib/make-toolbox-xml.jsmake-toolbox-xml.js
scratch-guisrc/lib/themes/default/index.jsindex.js
scratch-vmsrc/blocks/tutorialmod_dialogs.jstutorialmod_dialogs.js
scratch-vmsrc/engine/runtime.jsruntime.js
scratch-vmsrc/serialization/sb3.jssb3.js

Scratch commit hashes at the time of this tutorial
scratch-gui:        db1933b2aea9f9dbe51e0ad2d750a2550179314a
scratch-vm: d6420c4c9826d360adee118e0e9e255536be7f7c
scratch-blocks: 686df65cc6b5b3df37dc3204f56f443aa18c5085