In the first article I gave a minimal example showing how to build a simple experiment using jaysire and how to run it locally. In the original example, I created three separate trials and put them together into a timeline. This approach works well when your experiment is short and you don’t need to worry about randomisation, but most behavioural experiments are considerably longer, and require some degree of randomisation.

The goal in this article is to take the same experiment and extend it in three ways:

  • Avoid code duplication using timeline variables
  • Randomise the order of trials within a block
  • Repetition of blocks of trials

We’ll define our instruction set the same way we did last time, using trial_instructions() to create a browsable sequence of instruction pages:

Trial templates

In the original example, our next step was to define a specific trial using trial_html_button() response, in which the stimulus argument corresponded to a specific equation like “2 + 2 = 4”, and the choices offered to participants were to judge the equation to be “true” or “false”. This time around, we’ll do the same thing except we won’t specify the stimulus directly. Instead, what we’ll do is define a timeline variable using the variable() function. The insert_variable() function has only a single argument name, which tells jsPsych what to to call the timeline variable. So we can create a kind of “trial template” like this:

Attaching variables to timelines

Our next step is to specify what possible values the variable can have. Let’s do that by creating a character vector that lists all the equations we want to show people:

Now that we have specified the stimuli as an ordinary R variable, what we need to do is to link it to the trial template we defined earlier. To do this, we first “wrap” trial_template into a timeline, and use the set_variables() function to attach a variable to that timeline:

trials <- build_timeline(trial_template) %>%
  set_variables(my_stimulus = equations)

This might seem slightly odd, because in our first example we created all the trials individually and only wrapped them into a timeline at the very end. However, jsPsych allows you to nest timelines within other timelines, and this can be extremely useful. In this situation, what we have create is essentially a new “mini-timeline” that consists of six copies of the trial_template, each one using a different equation. This “templating” approach produces code that is much easier to write than if we had to use trial_html_button_response() six times, and as you might imagine this is much more efficient when there are hundreds of different stimuli!


So far, so good. However, one limitation with our code is that the experiment will run the six trials in the same order every time. If our experiment were running in R, what we could to is use the sample() function to shuffle stimuli, but that won’t work in this situation because the experiment will (eventually) run through a web browser. So if we want to randomise the trial ordering we need to use the randomisation tools built into jsPsych. We can do this by attaching parameters to the timeline that we have just defined using the set_parameters() function:

trials <- build_timeline(trial_template) %>%
  set_variables(stimulus = equations) %>%
  set_parameters(randomize_order = TRUE)

In this version, the trials timeline contains the same six copies of the template, but jsPsych will show them in a random order when the experiment is run in the browser.


We’re almost there. Suppose we want to create a “block randomised” design, in which all six items are presented in a random order, and then the same six items are repeated in a different randomised order. This kind of design is quite common in experimental psychology, and we can create one by setting the repetitions parameter for the timeline:

trials <- build_timeline(trial_template) %>%
  set_variables(stimulus = equations) %>%
  set_parameters(randomize_order = TRUE, repetitions = 2)


At this point we are done, more or less. We’ll still have to do the boring job of creating a final trial that tells the participant that the experiment is complete, and of course we’ll have to use the build_experiment() function to actually build the experiment! Once we’ve done that, we end up with the following as the complete code for the experiment:

You can check out a working version of the experiment here.