Plugins

Verge3D Puzzles Editor provides the ability to load your own custom puzzles, thus making it possible to extend the Editor's functionality with features you've always wanted.

Contents

Installing Plugins

Plugins are directories with a bunch of plugin-relevant files. Plugins should be placed inside Verge3D's puzzles/plugins folder in order to be recognized by the Puzzles Editor. And that's it! After reloading the Editor's page all installed plugins should appear at the bottom of the Editor's toolbox right after all the standard puzzle categories.

Plugin categories in the toolbox

Plugin Files Overview

A typical plugin is just a directory with an init.plug file containing general plugin settings and a bunch of *.block files each defining a single puzzle block. If your text editor supports syntax highlighting, then the HTML mode should work well for both file formats.

init.plug File Format

init.plug is a mandatory plugin file, which is used for specifying general plugin settings. In that file you can define what the toolbox entry looks like. Also you can add there some preliminary javascript code for your puzzles. Here's a simple example of what you can see in an init.plug file:

<category name="My Awesome Plugin" colour="green"> <label text="My Awesome Plugin v1.0"></label> <block type="myPuzzle"></block> <block type="doSomethingCool"></block> </category> <script> function code() { return `console.log('Powered by My Awesome Plugin!');`; } </script>

Category

The category part is an XML tree that defines how the plugin and its puzzle blocks are displayed inside the Puzzles Editor's toolbox. Although it is optional, still if you don't add it into the init.plug file then the plugin won't be loaded at all.

There are several options that you can set up via category:

Toolbox Entry Name

Specified via the name attribute: <category name="My Awesome Plugin"></category>

Toolbox Entry Color

Specified via the colour attribute: <category name="My Awesome Plugin" colour="green"></category> The color can be defined in one of the following formats:

Available Puzzles

To make a puzzle block available in the plugin's toolbox category it should be specified via the block element and its type attribute. The type attribute can reference such puzzles as:

Puzzles Order

Puzzle blocks appear in the toolbox in the order you define in the init.plug file: <category name="My Awesome Plugin" colour="green"> <block type="myPuzzle"></block> <block type="doSomethingCool"></block> <!-- <block type="testPuzzle"></block> --> <block type="anotherPuzzle"></block> </category>
Note how the commented out puzzle block "testPuzzle" isn't shown in the toolbox.

Text Labels

You can add text labels into the toolbox category via the label element: <category name="My Awesome Plugin" colour="green"> <label text="My Awesome Plugin v1.0"></label> <label text="Main Puzzles:"></label> <block type="myPuzzle"></block> <block type="doSomethingCool"></block> <label text="Other:"></label> <block type="anotherPuzzle"></block> </category>
Keep in mind that label is not suitable for displaying multiline text (i.e. no line breaks).

Separator Elements

You can add separator elements into the toolbox category via the sep tag. Separators can be used to change the distance between puzzle blocks. Its gap attribute specifies the gap width in pixels. The default distance (when not using sep) equals to 24 pixels. <category name="My Awesome Plugin" colour="green"> <block type="myPuzzle"></block> <sep gap="0"></sep> <block type="doSomethingCool"></block> <sep gap="80"></sep> <block type="anotherPuzzle"></block> </category>

Puzzle Blocks Available in the "init" Tab

By default puzzle blocks only available in the main and user-created tabs, but not in init. That's because the code generated by the init tab is executed before a Verge3D application is loaded and fully initialized. This means that puzzles intended to work with a 3d-scene, 3d-objects, materials, etc... are not suitable for using inside init and can crash the application. However, puzzles that don't require a 3d-scene to be available (e.g. those that preload resources or set up the UI) shouldn't have such problems and can be allowed in init.

In order to make a puzzle appear in the init tab's toolbox you need to set the allowInit attribute to true for the puzzle's block element (this also works with label and sep elements): <category name="My Awesome Plugin" colour="green"> <label text="My Awesome Plugin v1.0" allowInit="true"></label> <label text="Main Puzzles:"></label> <block type="myPuzzle" allowInit="true"></block> <block type="doSomethingCool"></block> <label text="Other:"></label> <block type="anotherPuzzle"></block> </category>
Note how the block and label elements without allowInit are not displayed in the toolbox.

Default Input and Field Values

If a puzzle block has block inputs (slots for connecting other puzzle blocks) and/or field inputs (non-block UI elements such as selectors, checkboxes, text fields, etc...), then you can specify their placeholder blocks and/or default values. This feature serves two purposes: it provides a hint for users on what can be plugged into an input slot, and it also makes using a puzzle block a bit more convenient.

Let's say that your puzzle block has an input named "MY_NUMBER". Here's how you can add a placeholder block of type math_number plugged into that slot: <category name="My Awesome Plugin" colour="green"> <block type="myPuzzle"> <value name="MY_NUMBER"> <block type="math_number"></block> </value> </block> </category> And here's what it will look like:


A placeholder block plugged into an input slot can also be a shadow block. Shadow blocks are basically the same as ordinary blocks except they are automatically replaced with a block that you insert into the corresponding input slot and they automatically appear back when you remove that block from the slot. This makes shadow blocks a bit easier to use than ordinary placeholder blocks.

Shadow blocks are defined almost the same way as ordinary placeholder blocks, the only difference is that the block element is replaced with the similar shadow element: <category name="My Awesome Plugin" colour="green"> <block type="myPuzzle"> <value name="MY_NUMBER"> <shadow type="math_number"></shadow> </value> </block> </category> And it will look like this:


Puzzle blocks can have statement inputs, which are inputs that usually wrap a series of child puzzle blocks. Let's say that your puzzle block has a statement input called "MY_STATEMENT". Then you can add a couple of placeholder blocks into that input as follows: <category name="My Awesome Plugin" colour="green"> <block type="myPuzzle"> <statement name="MY_STATEMENT"> <block type="addHTMLElement"> <next> <block type="setHTMLElemAttribute"></block> </next> </block> </statement> </block> </category> The statement element used here references the "MY_STATEMENT" input via the name attribute. And it also has some placeholder blocks added into the input. Also, the next element is used here for chaining a series of placeholder blocks. The result of that setup is shown below:


If your puzzle block has a checkbox field named "MY_CHECKBOX", then you can define its default state (TRUE - enabled, FALSE - disabled) like this: <category name="My Awesome Plugin" colour="green"> <block type="myPuzzle"> <field name="MY_CHECKBOX">TRUE</field> </block> </category> And here's the result:


Through using placeholder blocks and default field values you can define complex compound puzzles akin to what you can add into the Puzzles Library:
Code in init.plug for the complex puzzle setup on the picture above can look like this: <category name="My Awesome Plugin" colour="green"> <block type="myPuzzle"> <statement name="STATEMENT_0"> <block type="whenClicked"> <value name="VALUE"> <block type="objectList"> <field name="FIELDNAME">Cube</field> </block> </value> </block> </statement> <statement name="STATEMENT_1"> <block type="loadScene"> <value name="URL"> <block type="text"> <field name="TEXT">my_scene.gltf</field> </block> </value> </block> </statement> <statement name="STATEMENT_2"> <block type="show"> <value name="VALUE"> <block type="objectList"> <field name="FIELDNAME">something</field> </block> </value> </block> </statement> </block> </category>

Toolbox Subcategories

A category in the Editor's toolbox can have subcategories, which in their turn can also have subcategories, and so on... This feature is useful if you want to organize your plugin's puzzles into a tree-like structure.

This can be achieved by using nested category elements: <category name="My Awesome Plugin" colour="green"> <block type="myPuzzle"></block> <category name="1" colour="red"> <category name="1.1" colour="silver"> <block type="anotherPuzzle"></block> </category> </category> <category name="2" colour="blue"> <block type="doSomethingCool"></block> </category> </category>
Any category can contain both category and block elements at the same time (although it's not mandatory). That way it acts like a parent for subcategories and also provides a selection of puzzle blocks.

Script

The script element is an optional part of init.plug. It can be used to add some initialization code for your puzzles. Sometimes you might need to do heavy calculations and cache some data before any of your puzzles can be used - that's where script comes to rescue.

If you define a code() function inside script it will be used to generate the code that is executed once before any puzzles. The code() function should return a string containing javascript code. <script> function code() { // this line will be executed before any puzzles return `console.log('Powered by My Awesome Plugin!');`; } </script>

.block File Format

Plugin files with the .block extension are used to define single puzzle blocks, specifically, what a block can look like and the code that it should generate if added to a workspace area. A plugin can have no .block files at all. That can be useful if you want to create a toolbox category with just stock puzzle blocks (even including more complex block setups).

The name of a .block file is used to indicate which puzzle blocks should be included in the plugin's toolbox category.

Here's a minimal example of a .block file: <script> function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); } function code() { return `console.log('This is my first puzzle!');`; } </script> Here we have a single script element which consists of just two functions: template() and code(). template() is used to define the appearance of the puzzle block and code() returns a string containing the code that should be generated in place of this puzzle.

So, based on the example above we can expect our simple puzzle block to be green and to have a text label saying "myPuzzle":


And if added to a workspace it should print the following message into the browser console:

Template Function

This function is used to define the appearance of a puzzle block, for example, the block's color, what inputs should the block have, how can it be connected to other puzzle blocks, etc... The template() function receives a block parameter, which is an instance of Blockly.BlockSvg.

Please, note that this section is just a brief overview of how to create a custom puzzle block. For more detailed information on general customization check out the Google Blockly documentation about custom blocks and fields.

Block Color

Can be set via block.setColour like this: function template(block) { block.setColour('green'); } Colors have to be in one of the formats described here: color formats.

Block Tooltip

You can add a tooltip that appears when hovering above a block. The method for defining a tooltip is called block.setTooltip. The tooltip is useful for providing a user with a simple description of what the puzzle is intended for, how it works, what are the usage tips, etc... function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); // set tooltip block.setTooltip(`This is my first puzzle!`); }

Block Help URL

If the tooltip is not enough for documenting your puzzle you may also add a link to a website with more thorough documentation. This link will be used for the Help entry in the puzzle context menu (right click on a puzzle). This can be done by using the block.setHelpUrl method. All Verge3D standard puzzles are set up to refer to relevant documentation sections similar to how it's done in the following example: function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); // set help url link block.setHelpUrl('https://www.soft8soft.com/docs/manual/en/puzzles/Plugins.html#block_file_template_block_help_url'); }

Adding Inputs

Puzzle blocks can have input slots for plugging in other blocks. Also they can have non-block UI elements like checkboxes or text fields. There are 3 different methods for adding inputs: block.appendValueInput, block.appendStatementInput and block.appendDummyInput. They can be used as follows: function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); // add value input block.appendValueInput('MY_VALUE_INPUT'); // or statement input block.appendStatementInput('MY_STATEMENT_INPUT'); // or dummy input block.appendDummyInput(); } Each one of them adds different kind of inputs.

You can see the difference between those types of inputs on the picture below:

Arrangement of Inputs

Block inputs can be arranged either vertically (which is by default) or horizontally. The method for controlling that is called block.setInputsInline. function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); // add some inputs to showcase the arrangement option block.appendValueInput('INPUT_0'); block.appendValueInput('INPUT_1'); block.appendValueInput('INPUT_2'); // arrange inputs vertically block.setInputsInline(false); // or horizontally block.setInputsInline(true); } The vertical and horizontal input arrangements displayed below:

Adding Fields

The template() function allows adding such UI elements as text labels, checkboxes, drop-down lists, text inputs and more. Those UI elements are called "fields". They can be added to an input of any type, but if you don't want to additionally create input slots for puzzle blocks you should stick to using dummy inputs.

Fields are appended to an input by using the appendField method. The method receives 2 parameters: field and id. The first one is a field that you want to add, the way it's created depends on a particular field type. The second parameter is an optional field id (e.g. 'MY_TEXT_FIELD'). The id is often used for obtaining the field value when generating the puzzle code in the code() function.

When creating a field via API you can also specify its default value. This is usually done via one of the field's parameters. Anyway, a default value defined in init.plug's category always has a higher priority than the one defined here in the template() function.

Let's see how to use appendField for adding various fields to your puzzles.

Block Connections

Puzzle blocks can have input, statement and output connections. Input connections are added automatically for each input slot created and serve the purpose of plugging in child blocks. See how to create inputs here: adding inputs.

Statement and output connections are used for connecting blocks to a parent block or sibling blocks. There are several API methods for setting up such connections: block.setPreviousStatement, block.setNextStatement and block.setOutput.

The first and the second methods add a connection at the top and at the bottom of a puzzle block respectively, so the block can be connected from below/above to other blocks that have a matching connection. setOutput adds a connection at the left side of a block - this allows a block to be plugged into an input slot of a parent block. The output connection typically used for puzzle blocks that return a value, e.g. the result of some math calculations.

By default a puzzle block doesn't have any connections at all. In order to add a statement/output connection you need to call setPreviousStatement, setNextStatement or setOutput with true as the first argument. You can even have 2 statement/output connections on a single block, but there must be only these combinations: previous + next or next + output.

Here's how those connections can be added to a block: function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); // add previous connection block.setPreviousStatement(true); } or: function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); // add next connection block.setNextStatement(true); } or: function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); // add output block.setOutput(true); } And this is what they look like in the Puzzles Editor (from left to right: previous, next, output)

Input/Output Type Checking

By default all puzzle blocks that have suitable inputs/outputs can be connected with each other. Yet, that doesn't mean all blocks should be compatible. Let's say that we have a puzzle block returning an array of coordinates, while some other block has an input that expects an animation name. If we try to plug in the first block into the second one then things might not work as expected. The code generated from those puzzles can be invalid and even lead to a crash.

Fortunately, there's a way to resolve that situation. Every input and output can be assigned a type and only those blocks that have matching types can be connected with each other. In order to assign a type (or multiple types) to an input you should use the setCheck method. And the equivalent for outputs is block.setOutput (for general information about output and other connections see block connections). function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); // input that can only accept blocks of type 'Number' block.appendValueInput('MY_INPUT') .setCheck('Number'); // set this block's type to 'String' block.setOutput(true, 'String'); } In the example above the block has an input that can only accept blocks of type "Number" or of unspecified type (if no type was set via setOutput). The block also has the "String" output type, which means that it can be only plugged into an input having the "String" type or unspecified type (if no type was set via setCheck).

Also, both inputs and outputs can have multiple types. They can be set by providing an array of allowed types like in this example: function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); // this input accepts blocks of type 'Number' and 'Object3D' block.appendValueInput('MY_INPUT') .setCheck(['Number', 'Object3D']); // this block's output type is both 'String' and 'Animation' block.setOutput(true, ['String', 'Animation']); } Standard Verge3D puzzles use several certain input/output types, which you may borrow for your puzzles as well:

You are not limited with the types described above and it's even encouraged to come up with your own input/output types that suit your puzzles better.

Code Function

The code() function is used to provide javascript code that should be generated for the puzzle if it's added to a workspace. Generally, this is the place where you define the puzzle's logic and where you implement most of the puzzle's features.

The function is expected to return a string containing js code. The way it works is similar to how init.plug's code function works, except that in this case the code will be added and used as many times as how many puzzle blocks are added to a workspace. The code() function receives a block parameter - it's the same instance of Blockly.BlockSvg that's used in template().

Let's look at what you can do with the code() function.

Basic Code Generation

The very simple thing that code() can do is to return a string with a couple of lines of javascript code, which will be added into the resulting visual_logic.js file.
For example, the following code opens the standard browser alert dialog: function code(block) { return `alert('Test');`; } And here we just return a value of 1: function code(block) { return `1`; } - this example doesn't make much sense unless the block has the output connection. In that case the returned value can be accessed from a parent block that has this block plugged into one of the inputs.

And now for a bit more advanced example: function code(block) { return ` app.scene.traverse(function(obj) { obj.material = new v3d.MeshBasicMaterial({ color: new v3d.Color(Math.random(), Math.random(), Math.random()) }); }); `; } - here all objects get a new material with a randomly generated color.

Mitigating Code Bloat

By default, a puzzle's code is copied into the generated visual_logic.js file each time the puzzle is used on a workspace. It's not a problem if you have just a couple of lines of code. But if the code is bulky, complex and split into several functions that you might want to declare only once, then the default approach becomes inefficient and causes the resulting visual_logic.js file to bloat.

To deal with that you can utilize a special method called Blockly.JavaScript.provideFunction_. Let's demonstrate that with an example: function code(block) { var fun = Blockly.JavaScript.provideFunction_('myFunction', [` function ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_}(a, b, c) { console.log(a, b, c); } `]); return `${fun}(1, 2, 3);`; } Here we have a function "myFunction" defined via Blockly.JavaScript.provideFunction_, which means that no matter how many times the puzzle is used on a workspace, "myFunction" will be copied to visual_logic.js just once. Also, the value that is actualy returned from code() is just ${fun}(1, 2, 3);, which is basically the function call "myFunction(1, 2, 3);" that will be inserted into visual_logic.js for every such puzzle used on a workspace. And this is what we exactly would want from our puzzle, because "myFunction" only needs to be declared just once, and after that it can be called multiple times.

The first parameter in Blockly.JavaScript.provideFunction_ should be a unique function identifier. The returned variable fun is the name of the provided function (it's usually almost the same as the value passed in the first parameter, but can be different because the Puzzles Editor needs to ensure that the name is valid and there's no collisions with other functions/variables used on a workspace). That name (instead of the original "myFunction") should be used to call the provided function - that is how it's done in the part under the return statement.

Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ is used in the example exactly to tell the Puzzles Editor that it should check the name of the function "myFunction" against potential collisions and modify it if necessary.

Accessing Inputs and Fields

If a puzzle block has fields or input slots defined in the template() function, then you would most likely want them to affect what is generated inside the code() function. For example, a checkbox can enable or disable one of your puzzle's features.

The API methods used to access value inputs, statement inputs and fields are namely: Blockly.JavaScript.valueToCode, Blockly.JavaScript.statementToCode and block.getFieldValue.

Let's make a puzzle block that has both inputs and fields. Here's the full content of the .block file: function template(block) { // some basic styling block.appendDummyInput().appendField('myPuzzle'); block.setColour('green'); // add value input, statement input and checkbox field block.appendValueInput('MY_VALUE'); block.appendStatementInput('MY_STATEMENT'); block.appendDummyInput() .appendField(new Blockly.FieldCheckbox('TRUE'), 'MY_CHECKBOX'); } function wrapFn(contents) { return `function() {${contents}}`; } function code(block) { var myInput = Blockly.JavaScript.valueToCode(block, 'MY_VALUE', Blockly.JavaScript.ORDER_NONE) || `''`; var myStatement = wrapFn(Blockly.JavaScript.statementToCode(block, 'MY_STATEMENT')); var myCheckbox = block.getFieldValue('MY_CHECKBOX') === 'TRUE'; var fun = Blockly.JavaScript.provideFunction_('myFunction', [` function ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_}(input, statements, checkbox) { console.log('input value:', input); statements(); // execute puzzles from the MY_STATEMENT input console.log('checkbox state:', checkbox); } `]); return `${fun}(${myInput}, ${myStatement}, ${myCheckbox});`; } In this example the block defines a value input called "MY_VALUE", a statement input "MY_STATEMENT" and a checkbox field "MY_CHECKBOX". We obtain their values via the API described above, but before we pass them into "myFunction" they undergo some noteworthy changes: var myInput = Blockly.JavaScript.valueToCode(block, 'MY_VALUE', Blockly.JavaScript.ORDER_NONE) || `''`; - an input slot might have no blocks plugged into it, so we just ensure that in such a case we get an empty string by adding the *|| `''`* part at the end. function wrapFn(contents) { return `function() {${contents}}`; } ... var myStatement = wrapFn(Blockly.JavaScript.statementToCode(block, 'MY_STATEMENT')); - a statement input slot usually contains a group of statements. It is convenient to wrap them in a function (see what wrapFn does) in order to pass that function object as a parameter and then treat it as a callback. var myCheckbox = block.getFieldValue('MY_CHECKBOX') === 'TRUE'; - here the checkbox value is just compared against TRUE (see checkbox field description) to produce a boolean result.

In the end, all of the values can be passed into "myFunction" as follows: return `${fun}(${myInput}, ${myStatement}, ${myCheckbox});`; So, now you are able to use them however you want: var fun = Blockly.JavaScript.provideFunction_('myFunction', [` function ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_}(input, statements, checkbox) { console.log('input value:', input); statements(); // execute puzzles from the MY_STATEMENT input console.log('checkbox state:', checkbox); } `]);

Plugin and Block Errors

When developing or using plugins you can experience different errors related to a certain puzzle block or even a whole plugin. This section describes typical plugin and block errors and how to deal with them.

If something goes wrong during loading a plugin or initializing its puzzle blocks, then the Puzzle Editor prints a corresponding error message in the browser console. Usually, such error looks like one of the following:

PluginError(PLUGIN_NAME) ...
BlockError(PLUGIN_NAME/BLOCK_NAME) ...
Puzzle "PLUGIN_NAME/BLOCK_NAME" is not defined properly. Replaced with a dummy block.

- they refer to a specific plugin and a specific block that caused the error.

In case of a plugin error the whole plugin's category will most likely disappear from the toolbox. In case of a block error the affected blocks will be marked as invalid and will have a distinct look:

An invalid puzzle in the toolbox and on a workspace

Here's the list of the most common plugin and block errors:

BlockError(PLUGIN_NAME/BLOCK_NAME): error parsing .block file - "This page contains the following errors:error on line ..."

This means that there are XML errors in the corresponding .block file preventing it from being parsed. For example, the missing ending <script> tag leads to such error: <script> function template(block) {} function code(block) {}

BlockError(PLUGIN_NAME/BLOCK_NAME): error parsing .block file - "ReferenceError (SyntaxError, TypeError, etc...) ..."

The error occurs in case if the code in the corresponding .block file's <script> element contains a JavaScript error of the kind specified in the error message.

BlockError(PLUGIN_NAME/BLOCK_NAME): validation error - "TypeError: Child block does not have output or previous statement."

The block this error refers to has a child block plugged into it. However, the child block doesn't even have an output or a previous connection and therefore can not be used that way. This situation may happen either with puzzle blocks inside the plugin's toolbox category due to how they are configured in init.plug, and also this may happen with blocks actually used on a workspace.

BlockError(PLUGIN_NAME/BLOCK_NAME): validation error - "Error: Connection checks failed. Input "PARENT_INPUT_NAME" connection on "PLUGIN_NAME/BLOCK_NAME" block (id="BLOCK_ID") expected TYPE_PARENT, found TYPE_CHILD"

The block this error refers to has a child block plugged into it but the parent's input slot and the child's output connection have incompatible types. This situation may happen either with puzzle blocks inside the plugin's toolbox category due to how they are configured in init.plug, and also this may happen with blocks actually used on a workspace.

BlockError(PLUGIN_NAME/null): validation error - "TypeError: Unknown block type: PLUGIN_NAME/null"

This error means that the plugin's init.plug file refers to a block with no type attribute specified, which is not allowed. For example, this won't work: <category name="My Awesome Plugin" colour="green"> <block></block> </category>

BlockError(PLUGIN_NAME/BLOCK_NAME): validation error - "TypeError: Unknown block type: PLUGIN_NAME/BLOCK_NAME"

This error message usually appears after one of the "error parsing .block file" errors and simply indicates that the mentioned puzzle block wasn't properly loaded and initialized because of the original error.

BlockError(PLUGIN_NAME/BLOCK_NAME): error calling template() function ...

The corresponding .block file contains JavaScript errors inside its template() function.

BlockError(PLUGIN_NAME/BLOCK_NAME): error calling code() function ...

The corresponding .block file contains JavaScript errors inside its code() function.

PluginError(PLUGIN_NAME): error parsing init.plug file - "This page contains the following errors:error on line ..."

This means that there are XML errors in the plugin's init.plug file preventing it from being parsed. For example, the missing ending <category> tag leads to such error: <category name="MyAwesomePlugin" colour="green"> <block type="myPuzzle"></block>

PluginError(PLUGIN_NAME): error parsing init.plug file - "ReferenceError (SyntaxError, TypeError, etc...) ..."

The error occurs in case if the code in the corresponding init.plug file's <script> element contains a JavaScript error of the kind specified in the error message.

PluginError(PLUGIN_NAME): error calling code() function ...

The plugin's init.plug file contains JavaScript errors inside its code() function.

Puzzle "PLUGIN_NAME/BLOCK_NAME" is not defined properly. Replaced with a dummy block.

This error message usually appears after one of BlockError and/or PluginError messages and simply indicates that the mentioned puzzle block wasn't properly loaded and initialized due to the original errors. In order to still be able to load puzzles and maintain their operability to some degree, such blocks (both in the plugin's toolbox category and on a workspace) are replaced with special dummy blocks. The example of what a dummy block looks like can be seen on this picture.

Having Troubles with Puzzles?

Seek help on the forums!