creating interactive tutorials

TouchDevelop lets you author and distribute interactive tutorials where the user gets help from the system to create a particular script.

comments + code = tutorial

Tutorials consist of steps. Every step applies to an action. To create step(s) for an action named foo, create some actions in your tutorial named #1 foo, #2 foo, #2.5 foo, etc. Each of these actions will create one or more steps in the tutorial.
Let's take a look at an example:
function #1 main ()
## let's get started
We'll first print `hello`.
"hello world" → post to wall
And now we shall print 7.
7 → post to wall
end function
The first two lines are comments that describe the step. These use Markdown syntax. The next line is the actual body of the step, which can contain one or more lines of code. This is followed by the description and body for the next step.
In this example TouchDevelop displays the description to the user, and then makes them enter the body step as the body of the action main. Steps can be described in nested structures:
function #1 main ()
We start by writing a `for` loop:
for 0 ≤ i < 12 do
In every iteration we'll print `hello world`:
"hello world" → post to wall
end for
end function

easy start with the convert to tutorial plugin

We've created script plugin that takes an existing script and converts it into a tutorial. This is a great place to start building your own tutorials.
  • open the script to convert
  • tap on plugins
  • search and run the convert to tutorial plugin from TouchDevelop Samples
The plugin saves the generated tutorial into a new script that you can start editing.

making your scripts discoverable

A script with #docs #tutorials #stepByStep hashtags in the description is considered a tutorial. Use these hashtags so that other users can find your tutorial scripts.

testing tutorials

While authoring tutorials, you can easily test them to see what your users will see. Publishing is not required.
  • Tap the <- button to return to the script list.
  • Tap the follow button, which will start the tutorial.
  • On each dialog, you can tap on the rewind button to jump to a particular step.

interleaving steps

A step can not only add, but also replace preceding code. If the description of the step contains the macro {stdelete:N} then the steps cancels (removes) N preceding steps. Therefore, we can add {stdelete:1} as the last step to get the desired effect:
function #1 main ()
We start by writing a `for` loop:
for 0 ≤ i < 12 do
In every iteration we'll print **hello world**:
"hello world" → post to wall
{stdelete:1}
And now we change **hello world** to **goodbye**
"goodbye" → post to wall
end for
end function
We can also add code from earlier in the action to later steps. Normally steps are followed top-down, but steps with the {storder:N} macro in the description are executed after all of the steps without this macro, in order of N.
{storder} can be combined with {stdelete} to replace code in the middle.
The step order in the following example is:
1: Print "good morning".
2: Add a for loop.
3: Print "hello world".
4: Print i.
5: Delete the "good morning" line ({stdelete:1} is applied to the previous line in textual order, not the previous step (which was i)), and replace with 42.
function #1 main ()
We start by printing "good morning":
"good morning" → post to wall
{storder:1.5}
{stdelete:1}
And now let's replace "good morning" with `42`!
42 → post to wall
We start by writing a `for` loop:
for 0 ≤ i < 12 do
{storder:1}
Before every iteration we print `i`:
i → post to wall
In every iteration we'll print `hello world`:
"hello world" → post to wall
end for
end function

about adding new actions

In many tutorials, the user will have to create new actions. Let's take a closer look at how to do this.

the simple way

When the code of a step invokes an action foo that is not yet defined, the tutorial engine will automatically have the user create foo with the content that foo has in the tutorial (possibly in multiple steps). Note that there is no #2 foo involved.
private atomic function foo (
x : Number)
do
The first step will be displayed to the user before they are prompted to add an action. It's good to just use `{stcmd:empty}` as the body of the step, so you can write a separate description for the body of the action.
Let's add an action `foo` for printing `x`.
{stcmd:empty}
In the body, we just print `x`.
x → post to wall
end function
function #7 caller ()
We first create an `x`.
var x := 1
Here the tutorial will have the user add the action, and then proceed to adding the call. It will display this text, so you want to say something like:
And now, after we have added `foo`, we call it.
 foo(x)
end function

the powerful way

Let's say we need to create a sqr action that computes the square of a number. In the tutorial, we want to create 2 actions:
  • The numbered action that contains the steps, i.e. #2 sqr. This action will become a list of steps in the tutorial.
private function #2 sqr (
input : Number)
returns (
output : Number)
do
This code computes the square of ``input``.
output := input * input
end function
  • The same action with numbering in order to call it, i.e. sqr. This action is used to make calls from other actions.
private function sqr (
input : Number)
returns (
output : Number)
do
output := input * input
end function
Action and parameter names must be lower case without trailing spaces. The reason is that the tutorial engine normalizes the names entered by the user during the tutorial.

defining records and globals

the easy way

Global variables and fields of the records can be added via the promote to global and promote to field refactorings. All you need is an initialization expression before any uses, for example:
 my global := 0
We will have the user enter 0, tap on store in var, generating:
var my global := 0
and then have them tap on promote to global. Fields of locals can be also introduced this way, in particular the fields of page data object. You will just need to add initialization expressions in the initialize section of the page.

the powerful way

Records and globals are defined by using the {adddecl} macro (in its own comment line) in the description of the step. The body of the step then defines the record, global or field to be added. The body will not contribute to the body of the action. For example, let's create the tutorial that will create the following cloud table.
replicated
 
table
 
people
columns
name : String
age : Number
The tutorial action will look as follows.
function #4 add record ()
We start by adding the table and setting persistence mode.
{adddecl}
 people table
Now we add the `name` field.
{adddecl}
var p :=  people table → add row
p → name
And now we add the `age` field and set its type to `Number`.
{adddecl}
p → age
And finally, let's create an instance of it!
var people :=  people table → add row
end function
This will instruct the user to add an cloud table people table, then name field, and then age field. Finally, it will ask the user to add a single line of code (the last one above) to the body of the action. In particular p→name etc. are not going to be part of the add record action.
Record field should be introduced in their definition order.

including code in description

Use the {stcode} macro to inline the code that will be added in the next step.
{stcode}
You can also use one of the {box:...} macros. In particular, there is {box:block} macro, which doesn't add any border. For example:
function #1 main ()
{box:block}
We start by writing a `for` loop, like this one:
{hide}
var upper bound := 133
{/hide}
for 0 ≤ i < upper bound do
do nothing
end for
{/box}
for 0 ≤ i < 12 do
In every iteration we'll print `hello world`:
"hello world" → post to wall
end for
end function
The entire {box:block} is the description for the first step. Second (and final) step keeps its description.

talking heads

Hi friend! Sometimes, it is more engaging for the users to talk to an avatar.
Use the {box:avatar:<avatar id>} macro to create this dialog.

custom hashtags

Add hashtags to the template by using the sthashtags macro. The macro takes a semi-column separated list of tags (without the #).
{sthashtags:myTag,anotherTag}
Hashtags are useful to track which scripts got created by a tutorial.

custom validators

In more advanced tutorials you may want to directly guide the user through the first few steps, and then have them solve some problems on their own. The tutorial engine lets you provide custom actions that validate that the user indeed performed a given step. Such actions would usually look at the internal state of libraries used by the script, or look at the AST of the script itself.
If a step uses {stvalidator:action name} macro, the body of the step is not shown to the user. The user will be able to enter any code without obstructions. When they run the script, first the specified validator action runs and installs validation hooks of your choice. Then the user's main action runs. After the user stops the script, if tutorial→step completed was called by the validator the step is considered completed, otherwise the user needs to keep tweaking the solution. tutorial→show hint can be used to give some hints to the user.
Some notes:
  • If one step has a validator, all subsequent steps should also have validators. Otherwise TouchDevelop will have the user delete their code and enter the code of all the previous steps.

splash screen and conclusion

The comments on a public main action will be used in the splash screen. The comments on a public final action will be used in the conclusion dialog, after the user publishes.
So your user finished the tutorial, where does he go next? Use the following macro to control when tutorial tile shows up:
  • stnexttutorials takes a coma separate list of tutorial ids or none to disable that section. none also disables the script publishing step.
{stnexttutorials:turtle shapes tutorial, turtle tree tutorial}
  • stmoretutorials takes a topic id that will become the "more" button
{stmoretutorials:turtle tutorials}

meta-commands

The {stcmd:...} macro allows to specify specific editor commands.

run command

You can ask the user to run the program with {stcmd:run}. It needs to be included at the end of a step.

publish command

Users are automatically asked to publish the script at the end of tutorial but you can also introduce a publish step using {stcmd:publish}.

plugin command

The plugin command takes a plugin button name as argument.
{stcmd:plugin:my awesome plugin button name}
The tutorial engines does not check if the plugin or loaded and only matches based on the button name. Use the app→import feature in your tutorial to ensure that the plugin is loaded.

template and template name

You can use the {template:id} macro to specify an initial script to start the tutorial from. TouchDevelop always picks up the latest version of that script. However, it's recommended you can also use one of the pre-defined templates:
  • {template:empty} - with the main action
  • {template:emptyapp} - with main page
  • {template:emptyScriptPlugin} - with plugin action and #scriptPlugin description tag
If you don't want the user to start from an empty script, mark the first step with {stauto}} macro, like this:
function #1 main ()
{stauto}
for 0 ≤ i < 42 do
We got you started with a `for` loop. Now, let's print the square of `i`.
(i * i) → post to wall
{stcmd:run}
end for
end function
Also, the libraries from the tutorial will be copied to the template.
Use the {templatename:name} to specify a preferred name of the new script created by the user. In name, the token ADJ will be expanded to random adjectives like awesome, great, etc...
{templatename:ADJ game}

controlling hints

There are three modes of hints:
  • full - show hints for every button
  • semi - show hints for which line to edit, and show the goal, but don't show the hints for token insertion
  • free - no hints, only goal validation
The full and semi modes can be turned on for a step by using {sthints:full} or {sthints:semi}. The mode stays until it's overridden by another {sthints:...}. The free mode is turned on by using {stvalidator}.
If there are no {sthints} annotations, the tutorial engine places an implicit {sthints:semi} on the 5th step, and the default initial mode is full.

checkpoints

The {stcheckpoint} marks a step as a checkpoint and will be rendered specially in the tutorial.
Use the checkpoint to break down tutorials into logical sub-steps where students can get rewarded.
{stcheckpoint}

cheers

You can disable the random cheer that appears on each separate step.
{stnocheers}

controlling the user interface

You can specify the editor mode, block or pro using steditormode:
{steditormode:block}
It is also possible to closely control the buttons and widgets displayed to the user. TouchDevelop can hide button of advanced features by using the {widgets} macro. If you do not use it, all widgets are visible. If you use it, you specify the list of widgets that should be visible. The macro takes a coma separated list of widget identifier from the list below, e.g. {widgets:debugButton,codeSearch} macro.
  • debugButton shows the debug button
  • undoButton shows the undo button
  • updateButton shows the library update button
  • exportButton shows the export/help button
  • pluginsButton shows the plugin button
  • addNewButton shows the add new action, event button
  • logsButton shows the logs button
  • deployButton shows the deploy button
  • splitButton enables the split button (also see splitScreen)
  • codeSearch shows the Search code... search box
  • librariesSection shows the list of referenced libraries
  • promoteRefactoring shows the promote to data, promote to field, demote to var buttons
  • gotoNavigation shows the go to button
  • uploadArtInSearchButton shows the upload picture and upload sound in the inline art search
  • calcApiHelp tapping on the API helps open the help section
  • stripButton shows the strip while intelli-button and friends
  • splitScreen enforces the split-screen mode in landscape
  • scriptPropertiesManagement shows the section to revert changes, clone a script, etc...
  • scriptPropertiesExport shows the section to export the script to a native app
  • scriptPropertiesData shows the section to clear the local data or manage the cloud sessions.
  • scriptPropertiesInstrumentation shows the button to run under the profiler or with code covarge
  • scriptPropertiesPlatform shows the options to select which platform the script should be executed on.
  • scriptPropertiesSettings shows the checkboxes to tag a script as a library, web service, etc...
  • copyPaste allows to copy and paste lines of code in the editor
  • publishDescription allows to add a description when publishing a script
  • sendPullRequest shows the button to send a pull request when publishing a script
  • publishAsHidden shows the button to publish as hidden
  • moveToLibrary shows the button to move actions and variables to a new library
  • findReferences shows the button to find references for a given action or variable.
  • simplify shows the button to simplify an expression
  • tutorialGoToPreviousStep shows the go to previous step button in the tutorial dialog

fine-tuning experience with flags

The following flags are supported:
  • {flags:nosplit} - don't start in split screen mode
  • {flags:nodefaults} - don't fill out default values for calls (e.g., instead of math→random range(-100, 100) you will get math→random range([min], [max]))

imprecise matching

Normally the tutorial engine requires the code to be entered exactly as in the template. There is however a few exceptions:
  • the names of art resources are ignored; only the type has to match (i.e., if the tutorial has a picture resource in some place, any picture will do, but TouchDevelop will complain about sound)
  • differences in string literals are ignored by default, except for checking that the string is non-empty (if the string in the template is non-empty); this can be switched for particular string literals, for example {stprecise:"decl"} will make sure the string literal "decl" will need to be entered precisely - the setting is global for the tutorial
  • differences in concrete colors are ignored (i.e., colors→red is fine even if the tutorials says colors→blue; colors→random is not fine though)
  • any identifier name entered by the user, e.g. action name, parameter name, will be made lower case and white space will be truncated. Make sure that your tutorial follow these conventions.
Local variables introduced by store in var button are automatically named to match the tutorial; we do not allow any mismatch in variable or action names.

real time tracking

You can track anonymously the progress of your tutorial.

pixel tracking

You can receive real time progress of users for your tutorial by serving a 1x1 pixel image
{stpixeltracking:pixelurl}
The pixelurl should return a 1x1 image (preferably a small gif). TouchDevelop will automatically add the follow query arguments:
  • scriptid, id of the tutorial
  • index, current index in the tutorial
  • total, total number of steps
  • completed, whether the tutorial is finished
  • time, seconds since epoch when progress was recorded
  • anonid, an anonymized user id specific to this tutorial

event hubs

TouchDevelop can also inject data into an Azure Event Hubs using the {steventhubstracking} macro.
{steventhubstracking:<namespace>:<hub>:<SAS token>}
  • namespace is your service bus namespace
  • hub is the Event Hub name
  • SAS token is a valid Shared Access Signature token
When posting the data, TouchDevelop uses the anonimized user id as the device id.

show me some examples?

You can also learn by looking at our tutorial sources - they are scripts after all! Scroll down to the bottom of the view and select view as script.

how to get started?

You can start by modifying one of the following scripts:
Once you have added a few steps, go back to the script list and instead of the big orange edit tap on the small follow. This will let you test the tutorial.
When following tutorials that are under development (are not published yet) you get an additional rewind button in the dialogs that preceed each step. It will let you skip to any step in a tutorial.