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

For plugin developers
This helpful plugin contains examples of some typical puzzle blocks: ExamplePlugin.zip. Just unzip it into the puzzles/plugins folder and then check out the "Example Plugin" puzzle category.

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" color="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 color attribute: <category name="My Awesome Plugin" color="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:

To find out the type of a certain puzzle block you can use the "Print Puzzle XML Tree" option from the puzzle context menu:

That menu option prints the puzzle XML tree into the browser console. You can find there the puzzle type as well as the whole XML structure, which might come in handy when setting the default input and field values.

The "Print Puzzle XML Tree" menu option provides an easy way of adding a whole group of puzzle blocks to your plugin at once. This is useful for creating some sort of "snippets" consisting of connected puzzle blocks and putting them into your plugin, which makes it a bit similar to the Puzzles Library.

The following example explains how to do that:

Puzzles Order

Puzzle blocks appear in the toolbox in the order you define in the init.plug file: <category name="My Awesome Plugin" color="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" color="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>

label elements are not suitable for displaying multiline text, i.e. no line breaks.

label elements can also be stylized to some extent. They support a web-class attribute, which is intended for assigning a custom CSS class to the label element. The CSS rules for that class can be defined in init.plug's script section. This approach is illustrated in the following example:

<category name="Example Plugin" color="#a52a2a"> <label text="Example Plugin v1.0 by Soft8Soft" web-class="example-plugin__label"></label> </category> <script> const styleElem = document.createElement('style'); styleElem.innerHTML = ` .example-plugin__label .blocklyFlyoutLabelText { fill: #a52a2a; font-style: italic; font-weight: bold; text-decoration: underline; } `; document.head.appendChild(styleElem); </script>

And here's the result of applying the custom CSS rules:

When deciding what CSS class name to put into the web-class attribute it's recommended to consider some sort of CSS scoping, for example by using a prefix unique to your puzzles plugin, i.e. in the example above it's the "example-plugin" part of the "example-plugin__label" class. That way you less likely accidentally break any CSS classes already used on the page.

Separators

Separators can be used to change the distance between puzzle blocks. You can add separators into the toolbox category via the sep element. The gap attribute specifies the gap width in pixels. The default distance between blocks (when not using sep) equals to 24 pixels. <category name="My Awesome Plugin" color="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 allow-init attribute to true in the puzzle's block element (this also works with label and sep elements): <category name="My Awesome Plugin" color="green"> <label text="My Awesome Plugin v1.0" allow-init="true"></label> <label text="Main Puzzles:"></label> <block type="myPuzzle" allow-init="true"></block> <block type="doSomethingCool"></block> <label text="Other:"></label> <block type="anotherPuzzle"></block> </category>
Note how the block and label elements without allow-init 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 "myNumber". Here's how you can add a placeholder block of type math_number plugged into that slot: <category name="My Awesome Plugin" color="green"> <block type="myPuzzle"> <value name="myNumber"> <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" color="green"> <block type="myPuzzle"> <value name="myNumber"> <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 "myStatement". Then you can add a couple of placeholder blocks into that input as follows: <category name="My Awesome Plugin" color="green"> <block type="myPuzzle"> <statement name="myStatement"> <block type="addHTMLElement"> <next> <block type="setHTMLElemAttribute"></block> </next> </block> </statement> </block> </category> The statement element used here references the "myStatement" 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 "myCheckbox", then you can define its default state (true - enabled, false - disabled) like this: <category name="My Awesome Plugin" color="green"> <block type="myPuzzle"> <field name="myCheckbox">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" color="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>

Check out the "Print Puzzle XML Tree" context menu option. It helps in finding out the XML structure (the configuration of inputs and fields) of a puzzle block of interest.

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" color="green"> <block type="myPuzzle"></block> <category name="1" color="red"> <category name="1.1" color="silver"> <block type="anotherPuzzle"></block> </category> </category> <category name="2" color="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>

The initialization code returned by the code() function is added into the generated logic file only if the plugin's puzzles are actually used in the application (added on a workspace and not being disabled).

.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: <template color="green"> <dummy> <label>myPuzzle</label> </dummy> </template> <script> function code(block) { return `console.log('This is my first puzzle!');`; } </script> Here we have a <template> element which defines the appearance of the puzzle block. And also there is a <script> element with a code() function inside it. The code() function returns a string containing the code that will 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:

Block Template

The appearance of a puzzle block can be defined in two ways: via the <template> XML element and via the template() function. The former variant is more simple and easy to use. For example, this is what <template> of a typical puzzle can look like:

<template color="green" inline="true" output="Dictionary" tooltip="This is my first puzzle!" help="https://soft8soft.com" > <dummy name="myDummyInput"> <label>enable</label> <checkbox name="myCheckbox">true</checkbox> </dummy> <value name="myValueInput"> <label>input value</label> </value> </template> <script> function code(block) { return `console.log('This is my first puzzle!');`; } </script>

The other approach is to use the template() function. It's a function that you can define inside the <script> element. It can also be used to configure the puzzle appearance but this time through the Blockly JavaScript API rather than XML elements and attributes. It receives a block parameter, which is an instance of Blockly.BlockSvg.

The same block as in the example above can be rewritten by using the template() function as follows:

<script> function template(block) { block.setColor('green'); block.setInputsInline(true); block.setOutput(true, 'Dictionary'); block.setTooltip('This is a test puzzle!'); block.setHelpUrl('https://soft8soft.com'); block.appendDummyInput('myDummyInput') .appendField('enable') .appendField(new Blockly.FieldCheckbox(true), 'myCheckbox'); block.appendValueInput('myValueInput') .appendField('input value'); } function code(block) { return `console.log('This is my first puzzle!');`; } </script>

This approach is more flexible but requires knowledge of the corresponding APIs. It's especially useful if you need to do some non-trivial setup that can't be achieved via the <template> element. Moreover, you can use both <template> and template() simultaneously.

This section provides examples for both <template> (XML) and template() (JS) variants.

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

You can set block color to give your puzzles distinct appearance:

Can be set via the color attribute: <template color="green"></template>
Can be set via block.setColor: <script> function template(block) { block.setColor('green'); } </script>

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 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...

Can be set via the tooltip attribute: <template tooltip="This is my first puzzle!"></template>
Can be set via block.setTooltip: <script> function template(block) { block.setTooltip('This is my first puzzle!'); } </script>

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):

Can be set via the help attribute: <template help="https://www.soft8soft.com/"></template>
Can be set via block.setHelpUrl: <script> function template(block) { block.setHelpUrl('https://www.soft8soft.com/'); } </script>

Adding Inputs

Puzzle blocks can contain input slots for plugging in other blocks. Also they can have non-block UI elements such as checkboxes or text fields. There are 3 different types of inputs: value inputs, statement inputs and dummy inputs.

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

Use the <value>, <statement> and <dummy> elements to add inputs. Value and statement inputs must have a name (use their name attribute for that). Dummy inputs usually don't need names, they are merely containers for fields. <template> <value name="myInput"></value> <statement name="myStatement"></statement> <dummy> <checkbox name="myCheckbox">true</checkbox> </dummy> </template>
Use the block.appendValueInput, block.appendStatementInput and block.appendDummyInput methods to add inputs. Value and statement inputs must be named (via the name attribute). Dummy inputs usually don't need names, they are merely containers for fields. <script> function template(block) { block.appendValueInput('myValue'); block.appendStatementInput('myStatement'); block.appendDummyInput() .appendField(new Blockly.FieldCheckbox(true), 'myCheckbox'); } </script>

Arrangement of Inputs

Block inputs can be arranged either vertically (default) or horizontally.

Can be set via the inline attribute, which can be either true or false. false is for the vertical arrangement and true is for the horizontal variant. <template inline="true"></template>
Can be set via the block.setInputsInline method. The method receives a parameter, which can be either true or false. false is for the vertical arrangement and true is for the horizontal variant. <script> function template(block) { block.setInputsInline(true); } </script>

Adding Fields

You can add such UI elements as text labels, checkboxes, drop-down lists, text inputs and more into your puzzles. Those UI elements are called "fields". They can be added to inputs of any type, but if you don't want to additionally create input slots for puzzle blocks you should stick to using dummy inputs.

There are a couple of things that all fields have in common:

Let's see how to add various fields to a puzzle.

Field Alignment

Field elements in a puzzle block always belong to a particular input slot. Be it a single field or multiple fields per input, they are always rendered following a certain layout. One thing that can be changed about that is how fields are positioned inside an input, specifically which side they are aligned. You can make them align left (default), right and center.

To change the field alignment for a certain input use the align attribute on the corresponding input element. This attribute's valid values are: left, center and right. <template> <dummy align="left"></dummy> <value align="center" name="myValueInput"></value> <statement align="right" name="myStatementInput"></statement> </template>
To change the field alignment for a certain input use the setAlign method. Its first parameter should be Blockly.ALIGN_LEFT, Blockly.ALIGN_CENTER or Blockly.ALIGN_RIGHT. <script> function template(block) { block.appendDummyInput() .setAlign(Blockly.ALIGN_LEFT); block.appendValueInput('myValueInput') .setAlign(Blockly.ALIGN_CENTER); block.appendStatementInput('myStatementInput') .setAlign(Blockly.ALIGN_RIGHT); } </script>

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 more information on creating inputs here: adding inputs. Statement (previous and next) and output connections are used for connecting blocks to a parent block or sibling blocks.

Previous and next add connections 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.

Output adds a connection at the left side of a block - this allows the 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. You can add a single connection of any type to a puzzle block. You can add even 2 statement/output connections to a block, but only the following combinations are allowed: previous + next or next + output.

Here's how all those connections can be added to a block:

The previous statement connection can be enabled by setting the prev attribute to true: <template prev="true"></template>
The previous statement connection can be enabled by calling block.setPreviousStatement with true as the first parameter: <script> function template(block) { block.setPreviousStatement(true); } </script>
The next statement connection can be enabled by setting the next attribute to true: <template next="true"></template>
The next statement connection can be enabled by calling block.setNextStatement with true as the first parameter: <script> function template(block) { block.setNextStatement(true); } </script>
The output connection can be enabled by setting the output attribute to an empty string: <template output=""></template>
The output connection can be enabled by calling block.setOutput with true as the first parameter: <script> function template(block) { block.setOutput(true); } </script>

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 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.

For general information about output and other connections see block connections.

The output type can be specified via the <template>'s output attribute. The types that a particular input can accept are defined by the input's type attribute. <!-- the block's output type is 'String' --> <template output="String"> <!-- this input accepts only blocks of type 'Number' --> <value name="myInput" type="Number"></value> </template>
The output type can be assigned to a block by calling the block.setOutput method while passing true as its first and the desired type as its second parameter. The types that a particular input can accept are set by calling the setCheck method. <script> function template(block) { // this input accepts only blocks of type 'Number' block.appendValueInput('myInput') .setCheck('Number'); // the block's output type is 'String' block.setOutput(true, 'String'); } </script>

In the example above the block has an input that can only accept blocks of the type "Number" or of an 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" or an unspecified type (if no type was set via setCheck).

Inputs and outputs can also have more than one type:

In order to have multiple input/output types fill the corresponding type and output attributes with multiple type values separated by space: <!-- this block's output type is 'String' or 'Animation' --> <template output="String Animation"> <!-- this input accepts only blocks of type 'Number' or 'Object3D' --> <value name="myInput" type="Number Object3D"></value> </template>
In order to have multiple input/output types provide the array of types into setCheck and/or setOutput . <script> function template(block) { // this input accepts only blocks of type 'Number' or 'Object3D' block.appendValueInput('myInput') .setCheck(['Number', 'Object3D']); // this block's output type is 'String' or 'Animation' block.setOutput(true, ['String', 'Animation']); } </script>

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) { const fun = function() { app.scene.traverse(function(obj) { obj.material = new v3d.MeshBasicMaterial({ color: new v3d.Color(Math.random(), Math.random(), Math.random()) }); }); } return `(${fun})();`; } - 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 available inside the code() function. It is called Plug.provide(). Let's demonstrate how to use it with the following example: function code(block) { const fun = Plug.provide('myFunction', function(a, b, c) { console.log(a, b, c); }); return `${fun}(1, 2, 3);`; } Here we have a function "myFunction" defined via Plug.provide(), 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 Plug.provide() 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.

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: <template color="green"> <dummy> <label>myPuzzle</label> </dummy> <value name="myValue"></value> <statement name="myStatement"></statement> <dummy> <checkbox name="myCheckbox">true</checkbox> </dummy> </template> <script> function wrapFn(contents) { return `function() {${contents}}`; } function code(block) { const myInput = Blockly.JavaScript.valueToCode(block, 'myValue', Blockly.JavaScript.ORDER_NONE) || `''`; const myStatement = wrapFn(Blockly.JavaScript.statementToCode(block, 'myStatement')); const myCheckbox = block.getFieldValue('myCheckbox') === 'TRUE'; const fun = Plug.provide('myFunction', function(input, statements, checkbox) { console.log('input value:', input); statements(); // execute puzzles from the myStatement input console.log('checkbox state:', checkbox); }); return `${fun}(${myInput}, ${myStatement}, ${myCheckbox});`; } </script> In this example the block defines a value input called "myValue", a statement input "myStatement" and a checkbox field "myCheckbox". 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, 'myValue', 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, 'myStatement')); - 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('myCheckbox') === 'TRUE'; - here the checkbox value is just compared against "TRUE" 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: const fun = Plug.provide('myFunction', function(input, statements, checkbox) { console.log('input value:', input); statements(); // execute puzzles from the myStatement 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 Puzzles 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" color="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 either has an incorrectly defined <template> element or 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" color="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.


Sharing your Plugin

Once plugin developed and tested, feel free to share it by:

Having Troubles with Puzzles?

Seek help on the forums!