The graphical user interface and the block library can be customized without changing the code itself. The appearance of elements is defined in SVG elements, and their usage (lists of elements, behavior, code generated by VPL blocks) is defined in JSON. The location of SVG and JSON is typically in separate files when the application is served by an HTTP server, or in the main HTML file if the file is opened directly in the browser (in that context, loading separate files is forbidden by the browser for security reasons). "Files" stored in the HTML file are placed in script elements with two mandatory attributes: type, the script type, should be application/json
for JSON or application/svg
for SVG; id, the element id, plays the same role as the filename of real files.
The entry point of all the definitions is the file ui.json
(or script element with id="ui.json"
). Its content is an object {"key1":value1,"key2":value2,...}
.
Blocks are defined in ui.json
as an array property with key blocks
. If the value is null ("blocks":null
), the default built-in (non-SVG) block definitions are used; if the value is an empty array, the block library is empty.
The appearance of blocks is defined by SVG elements specified by URI strings with syntax filename#id
, where filename
is the SVG file name or the SVG script element id, and id
is the svg element id in that file.
Here are fragments of index-svg.html which illustrate the definition of the block button
. Property main
contains the URI of the svg element which is drawn for the button block. The filename part, blocks.svg
, refers to the script element which contains the svg the element belongs to; and the id part, Ev_Buttons
, is the element id in that svg.
<script type="application/json" id="ui.json">
...
"blocks": [
...
{
"name": "button",
"draw": [
{
"uri": "blocks.svg#event-button"
}
],
...
]
...
</script>
<script type="image/svg+xml" id="blocks.svg">
...
<g id="event-button">
...
</g>
...
</script>
In json, block contain the following properties:
-
"name"
(string, required): the block name, which should match VPL1 if possible. -
"type"
(string, required): one of"event"
,"state"
,"action"
, or"comment"
, which defines where the block is displayed (left for"event"
or"state"
, right for"action"
or"comment"
) and how it is used. -
"modes"
(array of strings, possibly empty, required): in which VPL mode the block is displayed. Contains"basic"
if displayed in basic mode,"advanced"
if displayed in advanced mode. This defines only the default block usage; customization can override it. -
"draw"
(array of objects, at least one element, required): list of the parts defining the block appearance including buttons, sliders, etc. Each part is described by an object with the following properties (only"uri"
and"js"
are implemented now):"uri"
(string, required unless"js"
exists): uri of the svg element ("filename#id"
, with same filename for all elements in the same block)"js"
(string, required unless"uri"
exists): JavaScript code which can draw to a canvas. The canvas context is stored in variablectx
, and the block parameters in variable$
. The block area is between 0 and 1000 along both axes; path coordinates as well as line width, font size etc. must be scaled accordingly. This area is not clipped. Code is bracketed betweenctx.save()
andctx.restore()
."scale"
(number, optional, default: 1): scale at which the element is displayed"dx"
(number, optional, default: 0): horizontal displacement"dy"
(number, optional, default: 0): vertical displacement
-
"defaultParameters"
(array of number, boolean or string values, optional): default values of the block parameters which define the state, in this order, of buttons (one value per button), radiobuttons (a single values for all radiobuttons), sliders (one value per slider), rotating controls (one value per control). -
"typicalParameters"
(same type and length as"defaultParameters"
, optional): values of the block parameters used to display the block in the block library. -
"typicalParamSet"
(array of elements the same type and length as"defaultParameters"
, optional): multiple values similar to"typicalParameters"
, to be used when the block has a very different appearance for different values of the parameters (e.g. in block"accelerometer"
where the first parameter is 0 for tap, 1 for roll angle, or 2 for pitch angle). These values are used when exporting libraries as HTML. -
"alwaysZoom"
(boolean, optional): true to zoom block when clicked, irrespectively ofminInteractiveBlockSize
andminTouchInteractiveBlockSize
. Default isfalse
. -
"buttons"
(array of objects, optional): multi-state button definitions. Each button is described by an object with the following properties:"id"
(string, required): id of the svg element corresponding to the button. It should be contained in the element identified by "main"."val"
(array of numbers, booleans or strings, required): possible values for the button state. Each click toggles to the next value."st"
(array of strings): style strings applied to svg elements when the corresponding value in val is active. Each style is defined by a fill and/or a stroke color, with the syntax"fill:color;stroke:color"
, or fill/stroke swapped, or one of them skipped without semicolon.
-
"radiobuttons"
(array of objects, optional): radio button definitions (exclusive buttons). Each button is described by an object with the following properties:"id"
(string, required): id of the svg element corresponding to the button. It should be contained in the element identified by"main"
."val"
(number, boolean or string, required): value for the set of radio buttons."st"
(array of 2 strings): style strings applied to svg elements when the radio button is unselected or selected, respectively. Each style is defined by a fill and/or a stroke color, with the syntax"fill:color;stroke:color"
, or fill/stroke swapped, or one of them skipped without semicolon.
-
"pushbuttons"
(array of objects, optional): definitions of buttons not associated to a specific parameter. The effect of clicking a pushbutton is to change globally the parameters, with more freedom (and complexity) than buttons or radiobuttons. They can be used to increment or decrement parameters. Parameters used only by pushbuttons can be reserved with"otherParameters"
. In pushbuttons objects, the following properties must be defined:"id"
(string, required): id of the svg element corresponding to the button. It should be contained in the element identified by "main"."newParameters"
(string, required): new value of the parameters when the button is clicked. The length of the parameter array must not be changed.
-
"sliders"
(array of objects, optional): slider definitions. Each slider is described by an object with the following properties:"id"
(string, required): id of the svg element corresponding to the slider, including the thumb. If the element's height is larger than the element's width, the slider is vertical, else it's horizontal. The element bounds are used to limit the position of the middle of the thumb. In the svg, the thumb should be place at a position such that it does not overflow the slider bounding box (the middle position should be safe)."thumbId"
(string, required): id of the svg element corresponding to the thumb in the slider (the part which can be moved)."lowerPartId"
(string, optional): id of the svg element clipped at the thumb position so that only the part on the left of, or below, the thumb is displayed. Can be used to replicate the slider element with a different color to better show the value."min"
(number, required): minimum value, stored in the block parameters."max"
(number, required): maximum value, stored in the block parameters."snap"
(array of numbers and/or strings, default: []): snap values to which the slider is attracted when the slider is within a relative distance of 10%. Numbers are fixed values; strings must contain a backtick-expression and are evaluated. They can refer to other parameters, typically other slider values (see "backtick-expressions" below)."discrete"
(non-empty array of numbers, default: null (continuous values possible)): like snap, but no other values are possible.
-
"rotating"
(array of objects, optional): rotating control definitions. Each control is described by an object with the following properties:"id"
(string, required): id of the svg element corresponding to the rotating element, including the thumb."centerId"
(string, required): id of the svg element whose center is the center of rotation."thumbId"
(string, required): id of the svg element corresponding to the control part which can be moved."numSteps"
(integer number): number of steps, positive for counting counter-clockwise, negative for counting clockwise. 0 means no rotation; ifnumSteps
is even, minimum value is-numSteps/2
(for a 180-degree rotation) and maximum value isnumSteps/2
; ifnumSteps
is odd, minimum value is-(numSteps-1)/2
and maximum value is(numSteps-1)/2
. If"numSteps"
property is not defined, value is in radians, counterclockwise, between -pi and pi.
-
"diffwheelmotion"
(object, optional): robot with differential wheel motion. The robot, seen from above, is defined by a svg element, with wheel axis on the x axis and positive motion up. Wheel motion is specified with two sliders which should be defined with"sliders"
. Contains the following properties:"id"
(string, required): id of the svg element corresponding to the robot."dx"
(number, optional): relative horizontal adjustment of the right wheel position (left wheel is moved symmetrically)."dy"
(number, optional): relative vertical adjustment of the wheels."adjscale"
(number, optional): scale adjustment for the traces; 1 (default) means that the wheels are at the svg element boundaries, <1 that they are inside the svg element boundaries."color"
(string, optional): trace color as a css color string (default:"black"
)"linewidth"
(number, optional): relative trace width. 1 (default) is the default line width of the block.
-
"score"
(object, optional): notes for a monophonic melody. Notes are drawn as hollow circles for half notes, solid circles for quarter notes, and not drawn for pauses. They're centered on a grid. The"score"
object contains the following properties:"id"
(string, required): id of the svg element where notes are drawn"numHeights"
(number, required): number of heights"noteSize"
(number, optional): relative note size adjustment factor. The normal size (default"noteSize"
of 1) isheight/numHeights
"linewidth"
(number, optional): relative line width for half notes. 1 (default) is the default line width of the block.
-
"otherParameters"
(number, optional, default 0): number of additional parameters, typically used by pushbuttons. -
"styles"
(array of objects, optional): style applied to SVG element. Each element contains the following properties:"id"
(string, required): id of the svg element style is applied, or not applied, to"complement"
(boolean, optional, defaultfalse
):true
to apply to all elements except with id"st"
(string, required): style string; usually contains backtick-expressions
-
"aseba"
(object, optional): code fragments to generate Aseba language source code. Code fragments contain Aseba source code. Except for"clause"
and"clauseAnd"
which contain expression fragments, they can contain muliple lines, comments, empty lines, terminated by linefeeds (\n
). Backticks mark JavaScript expressions which are evaluated to substitute block parameters; see below. The object contains the following properties (strings can be replaced with array of strings which are concatenated, to make the json file easier to read):"initVarDecl"
(array of strings, optional): code fragments for (global) variable declarations. Identical fragments (after backtick-expressions evaluation) are output only once."initCodeDecl"
(array of strings, optional): code fragments for subroutine declarations. Identical fragments (after backtick-expressions evaluation) are output only once."initCodeExec"
(array of strings, optional): code fragments for initialization. Identical fragments (after backtick-expressions evaluation) are output only once."sectionBegin"
(string, optional, event block): beginning of a section (typically anonevent
block). Identical sections are collected and a single sectionBegin and sectionEnd are output."sectionEnd"
(string, optional, event block): end of a section (typically unused for Aseba code)."sectionPreamble"
(string, optional, event block): code at beginning of sectionBegin/sectionEnd (enforce section even when the block is used only as state)"clauseInit"
(string, optional, event block): code fragments for clause initialization. Identical fragments in the same section (after backtick-expressions evaluation) are output only once after"sectionBegin"
. Used to initialize temporary values used in clauses."clause"
(string, optional, event block): clause expression (condition) used in"when"
Aseba statement for the whole block."clauseAnd"
(string, optional, event block): clause subsexpression."clause"
and"clauseAnd"
cannot be used in the same block."clauseAnd"
expressions are produced for each parameter; the whole clause is obtained by joining"clauseAnd"
expressions with the"and"
operator."clauseAlwaysEval"
(boolean, optional, default not): if true, clause or clauseAnd are in anif
statement instead ofwhen
."clauseAsCondition"
(string, optional, event block): used in lieu of "clause" when the block is added as a condition next to an event."statement"
(string, required, action block): code fragment for action."statement1"
(string, optional, action or event block): code subfragment for event cache or action."statement"
and"statement1"
cannot be used in the same block. "statement1" statements are produced for each parameter; the whole statement is obtained by concatenating "statement1" statements.
-
"l2"
(object, optional): code fragments to generate L2 language source code. Same properties as"aseba"
.
Action block are implemented with "statement"
or "statement1"
. If global variables are used, they are declared in "initVarDecl"
. Any initialization must be defined in "initCodeExec"
. Only one copy of each "initVarDecl"
and "initCodeExec"
code fragments is output. While they can contain multiple variables or commands, it is recommended to split them into smaller fragments to avoid writing to the final program unused code.
Event and state blocks are more involved. "initVarDecl"
and "initCodeExec"
have the same role as for action blocks. Basically, event blocks are conditions, but they are evaluated in two distinct contexts: as a single, instantaneous, unique occurrence (the "event" side); and as a state (the "state" side). Consider a single proximity sensor, and the clause defined as true when the sensor value is higher than a threshold. The event side occurs once every time the sensor detects a transition from a value lower than the threshold to a value higher. The state side is true when the current sensor value is higher. The event side is used for the first event block, the state side is used for all the other event blocks.
On the Thymio, few firmware-level events (what triggers "onevent"
in Aseba) correspond to our definition of the event side. The remote control and the timers do, capacitive buttons and proximity sensors do not. It is up to the program generated from VPL to abstract from the firmware and run as expected. Continuing from the single proximity sensor example and adding key event, consider the following VPL program:
[prox > threshold] [key center] -> [action1]
[prox > threshold] -> [action2]
Aseba code could be as follows (actually an array eventCache
is allocated instead of variables proxClose
and keyCenter
):
var proxClose
var keyCenter
proxClose = 0
keyCenter = 0
onevent prox
when prox.value > 500 do
proxClose = 1
end
onevent key
when key.center != 0 do
keyCenter = 1
end
onevent timer1
if (proxClose != 0) and (key.center != 0) then
# action1
proxClose = 0
end
if keyCenter != 0 then
# action2
keyCenter = 0
end
To support these blocks, the code definition is as follows:
{
"name": "prox",
"aseba": {
"initVarDecl": [
"var proxClose\n"
],
"initCodeDecl": [
"proxClose = 0\n"
],
"sectionBegin": "onevent prox\n",
"clause": "prox.value > 500"
}
},
{
"name": "key center",
"aseba": {
"initVarDecl": [
"var proxClose\n"
],
"initCodeDecl": [
"proxClose = 0\n"
],
"sectionBegin": "onevent key\n",
"clause": "key.center != 0"
}
}
When an event block has parameters, possibly with a vector of values, a single boolean variable must capture the whole transition from false to true, and be unique for each different set of parameters event when it is repeated in different instances of the same block. Parameters should be different enough so that the differences are obvious in the block appearance. An array variable eventCache
is declared automatically with the appropriate size.
A proximity sensor with a vector of 5 values could be defined as follows.
{
"name": "prox 5",
"aseba": {
"sectionBegin": "onevent prox\n",
"clauseAnd": "prox[`i`].value > 500"
}
}
The VPL program
[prox[2] > 500 and prox[3] > 500] -> [action]
would be compiled as
var eventCache = [0]
onevent prox
when (prox[2].value > 500) and (prox[3] > 500) do
eventCache[0] = 1
end
onevent timer1
if eventCache[0] then
# action
eventCache[0] = 0
end
Special blocks contain definitions for specific purposes. They cannot be manipulated by the user to build rules. Their "type"
property should be "hidden"
, and their name start with an !
.
"!empty event"
: contains the svg elements displayed as a hint on the left part of the rule to accept another event block.
"!empty action"
: contains the svg elements displayed as a hint on the right part of the rule to accept another action block.
"!init"
: contains initialization code, in initVarDecl
for variable declarations if any, initCodeDecl
for function declarations if any, and initCodeExec
for intialization code if any.
"!stop"
: contains the code to stop the robot, executed when the Stop button is clicked.
"!volume"
: contains the code to set the robot volume, from 0 (muted) to 10 (max). The volume is specified in the single parameter.
Example:
{
...
"blocks": [
{
"name": "!empty event",
"type": "hidden",
"draw": [ { "uri": "blocks.svg#event-empty" } ]
},
{
"name": "!empty action",
"type": "hidden",
"draw": [ { "uri": "blocks.svg#action-empty" } ]
},
{
"name": "!stop",
"type": "hidden",
"aseba": { "statement": "motor.left.target = 0\nmotor.right.target = 0\n" }
},
...
],
...
}
By default, all blocks defined in array "blocks"
are available in that order, with event and state blocks on the left and action and remark blocks on the right, possibly filtered by the customization. Blocks can be reorder with a simple array of names in the property "blockList"
of ui.json
. If this property is defined, missing blocks are totally ignored; they cannot even be used in programs loaded from files. Blocks with type "hidden"
are always available internally and must not be listed in blockList
array.
Code fragments, styles, and some other properties can contain backtick-expressions, i.e. JavaScript expressions enclosed between backticks in normal double-quoted JSON strings. The expression is evaluated and its result replaces the whole backtick-expression in the string. A string can contain multiple backtick-expressions. The following variables are defined:
$
: array of block parametersi
: index of the parameter (used inclauseAnd
andstatement1
code fragments and in slider's"snap"
property)rgb
: function which converts an array of RGB values between 0 and 1 to an RGB value suited for representing an RGB led (saturated colors are mapped to themselves, but[0,0,0]
(led switched off) is mapped to gray).
Property "miscSettings"
contains VPL global settings which aren't related to the user interface:
"advancedModeEnabled"
(boolean, defaulttrue
):true
to enable advanced mode,false
to have a single mode (basic); can be overridden by query option advmode (see below)"basicMultiEvent"
(boolean, defaultfalse
):true
to allow multiple event blocks in basic mode"advancedMultiEvent"
(boolean, defaultfalse
):true
to allow multiple event blocks in advanced mode"viewRelativeSizes"
(object, default{"vpl":1,"src":1,"sim":1}
): relative size of vpl, src and sim views
Even when blocks are mostly hardcoded in JavaScript, properties related to code generation can be specified in JSON overlays. In that case, the following property should be defined:
"hardcoded-gui"
: (boolean, defaultfalse
):true
to use built-in block definitions and overlay code generation properties defined in JSON.
Toolbars can also be defined with SVG elements. Buttons are identified with a string id, such as "vpl:new"
for the button which resets the VPL program in the VPL view. Redefining toolbars is the result of two independent things:
- toolbar elements, as an array of button identifies + spacing for each toolbar (currently
"vpl"
,"vpl2"
,"editor"
and"simulator"
); - button appearance, defined as sets of SVG elements for the different button states (normal, pressed, selected, disabled, or any combination).
Toolbars and buttons can be defined either directly in the main ui.json file (top-level property "toolbars"
and "buttons"
, respectively), or in overlay json files referenced in the top-level property "overlays"
of ui.json
. SVG files must always be enumerated in ui.json
, in the top-level property "svgFilenames"
.
Property "toolbars"
is an object with one property per toolbar, with name "vpl"
(main toolbar at top of vpl view), "vpl2"
(optional toolbar at bottom of vpl view between the event and action blocs), "editor"
(source code editor view) or "simulator"
(simulator view). Property values are arrays of strings. Each string corresponds either to a button id or to one of the following special values:
"!space"
, a fixed space slightly larger than the usual space, used to indicate subgroups in groups of related actions;"!stretch"
, a larger space calculated so that the whole toolbar fills the available horizontal space. All"!stretch"
spaces have the same length. They're used to separate groups of unrelated items;"!!space"
, like"!space"
but never discarded (see below)"!!stretch"
, like"!stretch"
but never discarded (see below)
When toolbars are customized by hiding some buttons, multiple "!space"
and "!stretch"
items may appear in sequences. They're collapsed into a single "!stretch"
, or a single "!space" for sequences of multiple "!space"
items only. Leading and trailing sequences of "!space"
and "!stretch"
are entirely removed. When spaces should be preserved (e.g. a leading stretch to flush buttons to the right), "!!space"
and "!!stretch"
items should be used instead.
Buttons for actions which are permanently disabled, such as "vpl:run"
when neither the robot nor the simulator is available, or "vpl:teacher"
when the user has a student role, are not displayed.
Here is the list of button ids for the VPL view (toolbars "vpl"
or "vpl2"
):
"vpl:close"
: close the VPL view"vpl:about"
: display an about box (modal box with HTML defined in property "about.html" of property "fragments" of ui.json)"vpl:help"
: display a help box (modal box with HTML defined in property "help.html" of property "fragments" of ui.json)"vpl:statement"
: display a statement box (modal box with HTML which can be sent by teacher from a connected dashboard)"vpl:readonly"
: read-only indicator when the program cannot be modified (new, load, advanced, undo, redo, duplicate, disabled, lock, trashcan, teacher commands are disabled)"vpl:new"
: reset VPL program to start a new program"vpl:save"
: download the VPL program"vpl:exportToHTML"
: export the VPL program to a self-contained HTML file"vpl:upload"
: upload VPL program to the central repository or to the teacher computer (state
is"empty"
if the program is empty,"uploaded"
if the program on the screen is the uploaded program,"canUpload"
if the program has never been uploaded, or"canUploadAgain"
if the program has already been uploaded but is not the one on the screen)"vpl:text"
: switch to the text programming language editor (Aseba, L2 or JavaScript)"vpl:text-toggle"
: toggle visibility of text editor (replaces"vpl:text"
and"src:close"
)"vpl:advanced"
: toggle between basic and advanced VPL mode"vpl:add-comment"
: add a comment to the VPL program"vpl:undo"
: undo last change"vpl:redo"
: redo last undone change"vpl:run"
: run the VPL program with the Thymio or the simulator (state
is"empty"
,"running"
,"error"
,"canLoad"
, or"canReload"
depending on the VPL program and whether it's been run and modified)"vpl:stop"
: stop the VPL program and blink the leds"vpl:connected"
: connection indicator (no action, always disabled; selected if connected to a robot, unselected if no connection with a robot; state is"monitored"
if connected with a supervisor application (teacher dashboard),"nonmonitored"
if disconnected, or""
(empty string) if no supervisor)"vpl:robot"
: toggle between all the robots specified in option "robot" in the query string (see below; hidden unless there are at least two robots;state
is the robot name, such as"thymio"
or"sim"
)"vpl:sim"
: switch to the simulator view"vpl:duplicate"
: duplicate a rule (drag target)"vpl:disable"
: toggle a rule or block between disabled and enabled states (drag target)"vpl:lock"
: toggle a rule or block between disabled and enabled states (drag target, not implemented)"vpl:trashcan"
: delete a rule or block (drag target)"vpl:teacher"
: toggle between the normal and the customization states"vpl:teacher-reset"
: reset the available toolbar buttons and VPL blocks to the standard sets"vpl:teacher-save"
: download customized state (like"vpl:save"
, but without the VPL program)"vpl:teacher-setasnew"
: toggle between setting current program and customized state as initial program after"vpl:new"
, or default empty program with customized state (automatic if"vpl:teacher-setasnew"
isn't used in top or bottom vpl toolbar)
The following ids are for passive text strings:
"vpl:message-error"
: vpl error message"vpl:message-warning"
: vpl warning message"vpl:message-empty"
: no error or warning message (placeholder for alignment)"vpl:filename"
: vpl filename and username, whichever are defined
Here is the list of button ids for the Editor view:
"src:close"
: close the editor view"src:new"
: clear the text program"src:save"
: download the text program"src:vpl"
: switch to the VPL view"src:locked"
: toggle between the locked state where the text program corresponds to the VPL program and cannot be edited, and the unlocked state where the text program can be modified"src:language"
: switch to the next programming language (Aseba, L2, JavaScript or Python);state
is"aseba"
,"l2"
,"asm"
,"js"
, or"python"
"src:disass"
: toggle between the text programming language and the bytecode disassembly (for Aseba and L2)"src:run"
: run the text program with the Thymio or the simulator (state
is"empty"
or"canLoad"
depending on the source code)"src:stop"
: stop the text program and blink the leds"src:connected"
: connection indicator (no action; enabled if connected, disabled if no connection)"src:sim"
: switch to the simulator view"src:teacher"
: toggle between the normal and the customization states"src:teacher-reset"
: reset the available toolbar buttons and VPL blocks to the standard sets
Here is the list of button ids for the Simulator view:
"sim:close"
: close the simulator view"sim:restart"
: restart the program with the robot in the middle of the playground"sim:pause"
: toggle the simulation between the execution state and the suspended state"sim:speedup"
: change the speedup factor between x1 (real-time), x2, x5, x10 (accelerated), :2 (slowed down);state
is the acceleration factor (0.5, 1, 2, 5, or 10)"sim:noise"
: toggle simulated noise for sensor measurements"sim:pen"
: toggle pen between up and down"sim:clear"
: clear the pen trace (revert to the ground map)"sim:map-kind"
: change the map being displayed between ground (for ground sensor, combined with pen traces), obstacles (for proximity sensors) and height (for acceleration sensors);state
is"ground"
,"obstacles"
or"height"
"sim:map"
: toggle the map being displayed between on and off"sim:vpl"
: switch to the VPL view"sim:text"
: switch to text programming language editor"sim:teacher"
: toggle between the normal and the customization states"sim:teacher-reset"
: reset the available toolbar buttons and VPL blocks to the standard sets"sim-event:forward"
: send a button.forward event to the simulated robot"sim-event:backward"
: send a button.backward event to the simulated robot"sim-event:left"
: send a button.left event to the simulated robot"sim-event:right"
: send a button.right event to the simulated robot"sim-event:center"
: send a button.center event to the simulated robot"sim-event:clap"
: send a mic event to the simulated robot"sim-event:tap"
: send a tap event to the simulated robot
Property "buttons"
is an array with one element per button appearance. Each button appearance is an object with the following properties:
"name"
: button name (see "Toolbar definitions" above)"state"
: array of strings which restricts when the appearance is used: "pressed" (the button is being clicked or tapped, or the target of a drop), "unpressed" (the button is not being clicked or tapped, nor the target of a drop), "selected" (the button corresponds to a state which is ON), "unselected" (the button corresponds to a state which is OFF), "disabled" (the action is disabled), "enabled" (the action is enabled). In addition, strings starting with "=" specify which state to select for multi-state buttons such as "src:language" or "sim:map"; for example "=aseba" for the "src:language" button would be used when the Aseba language is selected. The first appearance match is used; typically appearance with "state" set to ["disabled"], ["pressed"], ["selected"] (for toggle buttons only), and [] (normal appearance) are defined in that order."draw"
: array of objects defining the appearance of buttons, like for blocks (see above). They have a"uri"
property for svg or a"js"
property for JavaScript code, and optionally an"alpha"
property (number, 1=opaque, 0=transparent) and a"debug"
property (string, displayed centered over the widget). Elements in"draw"
are rendered starting with the first one, with the last one in the foreground. In JavaScript code ("js"
property), the canvas context is stored in variablectx
, and the button state in variable$
, an object with properties$.enabled
,$.disabled
,$.selected
,$.unselected
,$.pressed
,$.unpressed
, and$.state
. The button area is between 0 and 1000 along both axes; path coordinates as well as line width, font size etc. must be scaled accordingly. This area is not clipped. Code is bracketed betweenctx.save()
andctx.restore()
.
Elements of "buttons"
with id "vpl:message-error"
, "vpl:message-warning"
and "vpl:filename"
(not real buttons, but placeholders to display error or warning messages, or filename/username, in a toolbar) should not be redefined in SVG. The text style can be changed in css.
If the value of property "buttons"
is null
("buttons":null
), the default built-in (non-SVG) button definitions are used. Otherwise, undefined buttons are displayed as squares with the button id and properties displayed; this can be useful during development.
Property "widgets"
is an array with one element per widget. A widget is a static graphical element used in the graphical user interface. They're identified by one of the following names:
"vpl:then"
: placed between events and actions (colon in VPL1)"vpl:error"
: error marker displayed close to rules with errors (question mark in a circle in VPL1)"vpl:warning"
: warning marker displayed closed to rules with warnings (minor issues which still permit to run the program)"vpl:moreHigh"
: hint displayed at the top of block lib (events or actions) when overflow is scroll (see section "Stylesheet" below) and the blocks could be scrolled down to show more"vpl:moreLow"
: hint displayed at the bottom of block lib (events or actions) when overflow is scroll and the blocks could be scrolled down to show more"vpl:customize"
: displayed in lieu of vpl program during ui customization when"vpl:teacher"
is selected
Widgets are scaled to fill their css box (see below). The box id for widget "vpl:then"
is "widget-then"
, and so on.
Each widget appearance is an object with the following properties:
"name"
: widget name (see above)"svg"
: array of objects containing a"uri"
or"js"
property, like for blocks (see above), and optionally an"alpha"
property (number, 1=opaque, 0=transparent), and a"debug"
property (string, displayed centered over the widget). SVG elements are rendered starting with the first one, with the last one in the foreground.
If the value of property "widgets"
is null
("widgets":null
), the default built-in (non-SVG) widget definitions are used. Otherwise, undefined widgets are empty (nothing is displayed).
Here is an overview of the SVG subset which is supported. Unsupported features are ignored.
- elements:
circle
,g
,line
,path
,polygon
,rect
,svg
,text
- style properties:
fill
,font-family
,font-size
,opacity
,stroke
,stroke-dasharray
,stroke-dashoffset
,stroke-linecap
,stroke-linejoin
,stroke-miterlimit
,stroke-width
,visibility
- gradients:
linearGradient
,radialGradient
The general layout of the user interface is subject to one or multiple stylesheets. The syntax is based on CSS. Stylesheets must be enumerated in the property "css"
in the main ui.json
file or script element; the value is an array of filenames (or script id) as strings.
Currently, some style-related parameters are still fixed in JSON (see "Global style settings" below), but eventually all properties should be defined in CSS. Unknown element names, classes, pseudo-classes and properties are ignored.
Style properties follow CSS box model (see https://www.w3.org/TR/css-box-3/). Default padding, border and margin are 0. Default size is what's required for the content (such as a block or a widget bounding box), or the available width or height, or 0 for empty boxes (separators).
Box properties:
padding-left
,padding-right
,padding-top
,padding-bottom
padding
border-left-width
,border-right-width
,border-top-width
,border-bottom-width
border-left-style
,border-right-style
,border-top-style
,border-bottom-style
border-left-color
,border-right-color
,border-top-color
,border-bottom-color
border-left
,border-right
,border-top
,border-bottom
border
border-width
border-color
border-top-left-radius
,border-top-right-radius
,border-bottom-right-radius
,border-bottom-left-radius
border-radius
border-top-left-cut
,border-top-right-cut
,border-bottom-right-cut
,border-bottom-left-cut
(same as*-radius
, but straight cut instead of rounded)border-cut
(same as*-radius
, but straight cut instead of rounded)border-corner-length
(length of border visible from each corner)margin-left
,margin-right
,margin-top
,margin-bottom
margin
backdrop-color
(square box, typically to complement rounded or cut corners)background-color
background
(for background-color property only)box-shadow
(inset
and spread radius ignored, one shadow only)width
,height
min-width
,min-height
(priority overmax-width
andmax-height
if inconsistent)max-width
,max-height
color
font
overflow
(used in block-library only)vertical-align
(used to align blocks in rules)
Line properties:
color
line-width
line-style
line-cap
Values:
- lengths: floating-point value with unit (
px
,cm
,mm
,in
,pc
,pt
,vw
,vh
,vmin
,vmax
,ww
,wh
,wmin
,wmax
,%
), or 0 - angles: floating-point value with unit (
rad
,deg
,grad
,turn
) - colors:
#xxxxxx
or#xxx
or one of the colors defined in https://www.w3.org/TR/css-color-3/#svg-color - line styles:
none
,hidden
,dotted
,dashed
,solid
, ordouble
- line caps:
butt
,round
,square
- font: see https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#font-prop
border-left
,border-right
,border-top
,border-bottom
,line
: 1, 2 or 3 properties for line width (length), color and line style in any orderoverflow
:wrap
(default) orscroll
vertical-align
:top
,middle
(default), orbottom
Functions min
and max
are supported in lengths.
Box elements:
view
(classes:vpl
,sim
,src
)widget
(id:widget-error
,widget-warning
,widget-then
,widget-moreLow
,widget-moreHigh
; pseudo-class:small
)button
(classes:vpl
,sim
,src
,top
,bottom
; pseudo-class for#vpl-filename
:edited
)separator
(classes:vpl
,sim
,src
,top
,bottom
)toolbar
(classes:vpl
,sim
,src
,top
,bottom
)vpl
block
(classes:event
,event-main
,event-aux
,action
,state
,comment
(class of block),empty
,library
(as displayed in block-library elements); pseudo-class:small
(when they must be zoomed for interaction),only-child
(for classempty
only))block-container
(classes:error
,warning
; used only in rules, not in block-library)rule
(class:comment
; pseudo-classes:small
,edited
)block-library
(classes:event
(for event and state blocks),action
(for action and comment blocks))button-small
(small buttons in simulator)sim-controller
(area where robot control buttons and indicators are displayed)sim-playground-area
(box which fills the area where the playground is displayed)sim-playground
(box which fits tightly the area where maps are displayed and the robot can be located)overlay-rectangle
(box displayed over other element; classes:disabled
,button
,vpl
,rule
,block
,drop-target
,kbd-selected
,kbd-target
)hint
(box at bottom left where block and toolbar button hints are displayed)
Line elements:
conflict-line
(classes:error
,warning
)crossout-line
(classes:button
,vpl
,rule
,block
,library
; additional propertiesline-angle
andline-overflow
)
Text messages can be translated to languages other than English. Translations are defined in dictionaries where the key is the English message and the value is the translated value. Translation dictionaries are specified under the key "i18n"
at the top level. Here is a partial example:
{
...
"i18n": {
"fr": {
"Missing action block": "Il manque un bloc d'action",
...
},
"it": {
...
}
},
...
}
Languages and messages can be split into multiple overlays.
Some global style settings can be specified in a top-level object named "style"
. Here is the list of properties it can contain, their type and their default values.
-
"scrollbarThumbColor"
(string, default:"navy"
): color of scrollbar thumbs -
"scrollbarBackgroundColor"
(string, default:"#ccc"
): color of scrollbar background (rectangular shape behind the thumb) -
"scrollbarWidth"
(number, default: 5): scrollbar width in css pixels -
"blockLineWidth"
(number, default: based on block size): line width used in blocks -
"minTemplateSize"
(number, default:32
): minimum block size in libraries -
"minInteractiveBlockSize"
(number, default:60
): minimum block size where direct manipulation of interactive controls (buttons, sliders etc.) is possible; if smaller, a zoomed version is displayed when the block is clicked or touched -
"minTouchInteractiveBlockSize"
(number, default:120
): same as"minInteractiveBlockSize"
, but for touch events, typically on smartphones and tablets -
"eventRightAlign"
(boolean, default:false
):true
to align event blocks on the right -
"ruleMarks"
(string, default:"#bbb"
): color of rule marks (colon dots)
Some HTML and CSS documents are defined as string properties of the top-level object named "fragments"
. For additional flexibility, html can contain a simple iframe
element which loads a separate HTML document. Here is a definition for the About box:
"<iframe src=\"vpl-about.html\" style=\"width:100%;height:100%;border:none;\"></iframe>"
The following properties are used:
"about.html"
: html document displayed in the About box."help.html"
: html document displayed in the Help box."vpl-export-html.css"
: css written into html files generated by button"vpl:exportToHTML"
.
In documents "about.html"
and "help.html"
, UIROOT
is replaced with the location of ui.json
, or by global variable window["vplUIRoot"]
if defined.
The entry point of the web application is defined in vpl-main.js
, in an event listener function for "load"
. Options can be specified in query parameters, i.e. in key=value pairs, separated by ampersand following a question mark. In addition, if the variable window["vplQueryOptions"]
is defined (typically in a script element in the html file which contains VPL3), its string value is used for options not specified in the url's query string.
The following options are supported:
appearance
:classic
(icons and blocks defined in JavaScript) orsvg
(default) (icons and blocks defined in SVG and json).multiview
:true
(default) to enable the display of multiple views simultaneously (main vpl view, text source code and simulator),false
to force a single view filling all the available space.advmode
: false (default) to disable advanced VPL mode, true to enable itlanguage
: programming language the vpl program is converted to.aseba
(default),l2
(C-like syntax with functions, local variables, boolean and fixed-point values, and multi-dim arrays),asm
(assembly language for Aseba bytecode),python
, orjs
. Not all the languages are compatible with the Thymio or the simulator.cssdebug
:true
to display the padding and margin rectangles of css boxes, orfalse
(default).adv
:true
to enable advanced features such as the Aseba virtual machine disassembler, orfalse
(default).blur
: radius of blur filter applied to canvas in 0.1px units (default 0), to simulate vision deficiency.grayscale
: percentage of grayscale filter applied to canvas (default 0), to simulate grayscale printing, low-quality displays such as beamers where color shifts are common, or vision deficiency.view
: list of initial views (defaultvpl
). Views (vpl
,src
orsim
) are separated by+
.robot
: device(s) code is sent to for execution.thymio
for a Thymio via asebahttp (supported language:aseba
),thymio-tdm
for a Thymio via the Thymio Device Manager (supported language:aseba
),sim
for the simulator (supported languages:aseba
,l2
, andjs
), or undefined for no execution. Multiple devices can be specified, separated with+
; e.g.robot=thymio-tdm+sim
. In that case, button"vpl:robot"
toggles between devices. Connection parameters can be passed as hash parameters (same as query parameters but after the hash character '#' instead of question mark '?'). Forthymio
,asebahttp=...
specifies the url of asebahttp or Thymio Web Bridge; the default isasebahttp=http://127.0.0.1:3000
if VPL is served as a local file, or the same http server as the one serving VPL if it's served over http(s). Forthymio-tdm
,w=...
specifies the url of the websocket (typicallyw=ws://ip:port
), andpass=...
the password (default: empty); the default isw=ws://localhost:8597
, i.e. the Thymio Device Manager running locally with its default port. With a password, it could bew=ws://10.0.0.200:8597&pass=ABCDEF
.role
:student
(default),teacher
(options to customize the user interface and vpl blocks), orteacher1
(options to customize only the vpl blocks).ui
: filename of the main json file (defaultui.json
)uilanguage
: 2-letter language code used to translate messages (default:en
; otherwise, as defined in dictionary"i18n"
of the user interface json file)user
: username displayed in the"vpl:filename"
indicator (overrideswindow["vplUsername"]
)shortcuts
: true or false to override the default setting (default:true
)accessibility
: list of accessibility features, separated by+
. Default: none. Supported:"kbd"
to edit vpl with keyboard.
VPL is started by code in a "load" event listener defined in vpl-main.js. Some customization is possible using global variables. To avoid interferences with Google Closure Compiler, they are accessed as window["vplXXX"]. Here is a partial list:
window["vplApp"]
:A3a.vpl.Application
objectwindow["vplIsProgramChanged"]
:function()
to check if the vpl program has been changed since it has been loadedwindow["vplGetProgramAsJSON"]
:function(libAndUIOnly)
to get vpl program as json, or block lib and UI configuration iflibAndUIOnly
is truewindow["vplGetUIAsJSON"]
:function()
to get UI and block selection as jsonwindow["vplQueryOptions"]
: can be set to override the query string (what follows the question mark in the url); see section above for options.window["vplCommandServer"]
: can be set to anA3a.vpl.Com
object to supervise the applicationwindow["vplDisableResize"]
: can be set to true to disable full-window modewindow["vplUsername"]
: can be set to a string to display the username in"vpl:filename"
indicatorwindow["vplUpload"]
: can be set to afunction(string filename, string json):void
to implement the"vpl:upload"
commandwindow["vplNextProgram"]
: can be set to afunction(string currentFilename, string? currentJsonProgram):nextJsonProgram
to implement"vpl:nextProgram"
command; ifcurrentJsonProgram
isnull
, just get a json containing a"filename"
property for the next program; otherwise should save and return either actual program with"filename"
property, or just object with"filename"
property if the program is provided asynchronously; ornull
if nothing is available; when programs are available, should be cyclicwindow["vplListenToCom"]
: can be set to a function(msg):void to listen to messages sent by a supervisor application (teacher dashboard)window["vplSendToCom"]
: function(data):void to send a "client" message to a supervisor application (teacher dashboard)window["vplStorageGetFunction"]
: can be set to avoid function(string filename, function(string jsonProgram, Object= options))
to get a file. Called at launch; if a program can be read (e.g. to restore a program saved tolocalStorage
in a previous session), should call the function passed as 2nd argument with the json program and (optionally) a dictionary with the (optional) following entries: string"filename"
(a filename which overrides the one passed tovplStorageGetFunction
), boolean"readOnly"
(true
to make the program read-only), boolean"fixedFilename"
(true
to disable edutability of program filename; by default same as"readOnly"
), boolean"customizationMode"
(true
to switch to ui customization mode like with command"vpl:teacher"
), boolean"setAsNew"
(true
to use the program as the initial state after"vpl:new"
, like with command"vpl:teacher-setasnew"
)window["vplUIRoot"]
: url (relative to document) used to override location of ui.json to defineUIROOT
inabout.html
andhelp.html
window["vplSimMaps"]
:"merged"
for distinct maps (buttons"sim:map-kind"
and"sim:map"
), or comma-separated map names for merged maps (buttons"sim:map-height"
,"sim:map-ground"
, and/or"sim:map-obstacles"
); default is "ground,height,obstacles"window["vplConfig"]
: can be set to configuration options:"ignoredCommands"
is an array of command ids which are discarded and not available in the configuration modewindow["vplConvertToHTML"]
:function(json, isVPL3UI)
to convert the content of a .vpl3 (ifisVPL3UI
is false) or a .vpl3ui file (ifisVPL3UI
is true) to a static HTML filewindow["vplConvertMDToHtml"]
:function(md)
to convert simple markdown to an html fragment (block-level elements such as h1, p, etc.)window["vplTextFieldInputEvents"]
:true
to useinput
events of an invisible<input>
element for text field input;false
to usekeydown
events; default istrue
for Android,false
for other platformswindow["vplConnections"]
: dictionary of additional robot connection methods; keys are what's specified with query optionrobot
and values are functions without argument which return an instance of a subclass ofA3a.vpl.RunGlue