This type of playground takes a student step by step through a feature of Babylon.js at the same time as higlighting the code used by that feature. The whole of the code exists in the playground editor but any distracting code can be hidden from the user. Generally the student should not be given the facility to edit the code or to use all features of the playground since doing so would destroy the tutorial they are trying to follow.
Below are three PBT examples to give you an idea of what is possible.
However since they are uneditable it is not possible to see how they are written. Links to guides on writing them are:
Starter Guide
Slider Guide
Intermediate Guide
Advanced Guide
To help in the coding of a PBT several functions are provided to manipulate the text in the playground editor and to create basic dialogue boxes using the Babylon.GUI. While editor manipulation needs the functions provided any method of writing a user interface that works with Babylon.js is possible.
The other important thing to consider is where to write the PBT code. Once the code is in the playground editor and 'Run' or 'Save'd the text of the code will be amended by its own code. For this reason it is better to write it externally to the playground. More on this later.
Think about the playground code you want to demonstrate and write it in the usual way
var createScene = function() {
//Usual PG code
return scene;
}
To start a new tutorial you need a 'new PBT()'
var createScene = function() {
//Usual PG code
var pbt = new PBT();
return scene;
}
In the rest of this section consider pbt as the newly created PBT.
hideMenu removes all the menu items from the menu bar except the title and the drop down choices of example playgrounds.
pbt.hideMenu()
editOff makes any code in the playground uneditable
pbt.editOff();
editOn allows the code in the playground editor to be edited. This is needed when any line changes need to be made by the code itself. When left on a user can also edit the text in the playground tutorial.
pbt.editOff();
clearDecorLines clears all decorations on all lines and will lighten all text.
pbt.clearDecorLines()
setDecorLines emphasises lines by adding decoration to them and darkening text. Lines to be decorated are passed as start line, end line pairs in an array.
pbt.setDecorLines([27, 27]); //decorates line 27 only
pbt.setDecorLines([3, 15]); //decorates lines 3 to 15 inclusive
pbt.setDecorLines([10, 17, 25, 31]); //decorates lines 10 to 17 and lines 25 to 3
replaceLines replaces the text in the given line range with the given new text. Only one range of lines is possible which is passed as an array pair.
pbt.replaceLines([13, 13], "mesh.rotation.x = Math.PI/4"); //replaces line 13 with one line of text
pbt.replaceLines([15, 15]), "mesh.position.x = 4;\r\nmesh.position.y = 6;\r\nmesh.position.z = -2;"); // replaces line 15 with multiple lines
pbt.replaceLines([23,28], "//All Gone"); //replaces lines 23 to 28 with a single line
replaceText inserts text in the given line from the start to end position.
pbt.replaceText(12, 3, 8, "WORLD"); // On line 12 replaces the characters from 3 to 8 with WORD
hideLines hides the lines passed as start and end pairs in an array. Each call to hideLines only hides those lines given in the array all other lines become shown.
pbt.hideLines([27, 27]); //hides line 27 only, all other lines are displayed
pbt.hideLines([3, 15]); //hides lines 3 to 15 inclusive only, all other lines are displayed
pbt.hideLines([10, 17, 25, 31]); //hides lines 10 to 17 and lines 25 to 31 only, all other lines are displayed
hideRange hides the range of lines passed as start and end pairs in an array. The method hideRange adds the range of lines given to lines already hidden.
pbt.hideRange([27, 27]); //hides line 27 together with already hidden lines
pbt.hideRange([3, 15]); //hides lines 3 to 15 together with already hidden lines
pbt.hideRange([10, 17, 25, 31]); //hides lines 10 to 17 and lines 25 to 31 together with already hidden lines
showRange displays the range of lines passed as start and end pairs in an array. The method showRange only affects the given line range if previously hidden using hideRange with the same line range.
pbt.showRange([27, 27]); //displays line 27 together with already displayed lines
pbt.showRange([3, 15]); //displays lines 3 to 15 inclusive together with already displayed lines
pbt.showRange([10, 17, 25, 31]); //displays lines 10 to 17 and lines 25 to 31 together with already displayed lines
getLineText returns the text on the given line number.
var lineText = pbt.getLineText();
There are two dialogue boxes that can be created for a PBT.
This consists of an image area, a text area and 'Prev' and 'Next' buttons.
Whilst a 'Prev' button is available the difficulty of undoing any actions already done means that this can usually be hidden.
var dialog = new PBT.StandardDialog(options)
There are a number of options available on creation
option | value | default value |
---|---|---|
text | (String) | "Playground Based Tutorial" |
width | (string) | "50%" |
height | (string) | "25%" |
top | (string) | "0px" |
left | (string) | "0px" |
verticalAlignment | (number) | BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP |
horizontalAlignment | (number) | BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT |
useImage | (boolean) | true |
imageUrl | (string) | path to BJS PBT logo |
options = {
left: "0.5%",
top: "0.2%",
text: "Read on for the difference between .rotation and .rotate and follow to the end for examples."
}
var dialog = new pbt.StandardDialog(option);
dialog.hidePrev();
Setting 'useImage' to 'false' extends the width of the text area.
There are a number of methods available to change an informative dialogue box after construction.
dialog.setText("More Information");
dialog.setWidth("20%");
dialog.setHeight("45px");
dialog.setTop("5px");
dialog.setLeft("15%");
dialog.setHorizontalAlignment(BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER);
dialog.setVerticalAlignment(BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM);
dialog.show(); //information box visible
dialog.hide(); //information box hidden
dialog.showNext(); //next button visible
dialog.hideNext(); //next button hidden
dialog.showPrev(); //prev button visible
dialog.hidePrev(); //prev button hidden
Two further methods getNextButton and getPrevButton allow functions to be added to the 'Next' and 'Prev' buttons.
dialog.getNextButton().onPointerUpObservable.add(function() {
tutorIndex++;
tutorial.setText(tutorTexts[tutorIndex]);
nextAction(tutorIndex);
});
This selection dialogue box contains button groups of 'radio', 'checkbox' or 'slider' buttons. Each group can contain only one type of button but you can mix and match the types of groups in one box if you wish.
Fig 1.
Button groups are constructed using the ButtonGroup
function
var myRadioGroup = new PBT.ButtonGroup("Name for Radio Group", "R");
var myCheckboxGroup = new PBT.ButtonGroup("Name for Checkbox Group", "C");
var mySliderGroup = new PBT.ButtonGroup("Name for Slider Group", "S");
The first parameter is the name of the group which will appear as the group header in the selection box. The second optional parameter gives the type of button, "radio" or "R" for a radio
button, "checkbox" or "C" for a checkbox
or "slider" or "S" for a slider
. The default is "checkbox" so can be missed out if this is the type of button you want. In the case of 'radio' buttons the button group also places together those buttons that react together. For "checkbox" and "slider" buttons the grouping is just cosmetic.
The buttonGroup
object has two methods addButton
for adding a "radio" or "checkbox" button and addSlider
to add a slider.
The addButton
method takes three parameters and creates the appropriate radio or checkbox button.
myRadioGroup.addButton("Radio Button Name", function, false)
myCheckboxGroup.addButton("Checkbox Button Name", function, true);
The first two parameters are required and the third optional.
For the above Fig 1. the code for the button groups could be
var boxGroup = new pbt.ButtonGroup("Box Code");
boxGroup.addButton("Hide", hideBoxCode, true);
var animGroup = new pbt.ButtonGroup("Anim Code");
animGroup.addButton("Hide", hideAnimCode, true);
var spaceGroup = new pbt.ButtonGroup("Space", "radio");
spaceGroup.addButton("WORLD", worldSpace, true);
spaceGroup.addButton("LOCAL", localSpace);
Fig 2.
The addSlider
method takes seven parameters
mySliderGroup.addSlider("Slider Name", function, "units", label function, minimum, maximum, start);
For Fig 2. the code could be
var slider = new pbt.ButtonGroup("Angle", "S");
slider.addSlider("X axis", boxAboutX, "degs", updateLabelX, 0, 2 * Math.PI, 0);
slider.addSlider("Y axis", boxAboutY, "degs", updateLabelY, 0, 2 * Math.PI, 0);
slider.addSlider("Z axis", boxAboutZ, "degs", updateLabelZ, 0, 2 * Math.PI, 0);
These groups can then be added to a new SelectionDialog
box in the groups
option.
var selector = new SelectionDialog(options);
The options for a selection dialogue box are
option | value | default value |
---|---|---|
width | (string) | "50%" |
height | (string) | "25%" |
top | (string) | "0px" |
left | (string) | "0px" |
verticalAlignment | (number) | BABYLON.GUI.Control.VERTICA\L_ALIGNMENT_BOTTOM; |
horizontalAlignment | (number) | BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT |
groups | (array) REQUIRED |
var selector = new pbt.SelectionDialog({groups:[boxGroup, animGroup, spaceGroup]});
or
var sliderSelector = new pbt.SelectionDialog({groups: [slider]});
or possibly
var options = {
width: "40%",
height: "10%",
top: "20%",
groups: [boxGroup, animGroup, spaceGroup, slider]
}
var selector = new pbt.SelectionDialog(options);
To repeat an earlier statement; while it is possible to write a PBT directly into the playground editor it is not a good idea. Running and saving your code in the playground changes the code and you are likely not to bele to get the original text back.
The simplest way is to use your favourite text editor and save as a text file. When you think it is ready to try copy the text and paste it into the playground. Click the RUN button to test, avoiding the SAVE button until you are sure all is working well. You will probably find it needs many adjustments until it is correct. More than anything is getting the line numbers correct. As you find you need to add and edit your code these line numbers keep changing.
For those of you familiar with Node.js, git and npm there is another way that avoids the copying and pasting part until you have a finished working copy. For this you will need to run a version of the playground locally.
Clone Babylon.js
git clone https://github.com/BabylonJS/Babylon.js.git
In the Babylon.js directory install gulp globally
Change to the Playground directory and npm install
Change to the Tools/Gulp directory and npm install
To write a tutorial use your favourite IDE (VSCode for example) to open the Playground directory. Inside this there is a scripts
folder, save your Javascript tutorial code in this folder. Also in this folder is a scripts.txt
file that lists all the files in the scripts
folder and makes then accessible to the Scenes drop down list at the top right of the playground. Add your file name to the list. Now you can write and edit your file, run a local version of the playground and by choosing it from the list test it.
To run a local version of the playground make sure you are in the Tools/Gulp directory of your copy of Babylon.js and npm run start
Once the server is running in your browser type address http://localhost:1338/Playground/index.html to run the playground.