Introduction
This document is a guide and reference book for working with the file
experiment_template.html, which is the core component of the
mousetracking template
(Download
all files here). The template is supposed to function as a tool box
for creating mouse-tracking experiments according to your individual
purposes. The experiments in this script are created with jsPsych, a
free JavaScript-based application for experiment creation. The script
allows you to choose between three different experiment
scenarios. In addition, the template includes the code chunks for
pre- and post-experiment surveys.
This tutorial was created by Christoph Jörger. The mousetracking
template is joint work by Zibu Lin, Christoph Jörger and Johannes
Gerwien. If you find errors, have suggestions for improvement, or if you
want to join us in extending the template, get in touch with
Johannes
Gerwien .
The order of mention/discussion of individual template elements
throughout this document does not always reflect the structure of the
script itself, but rather follows a functional approach aiming at
familiarizing you with the template’s most important components.
Therefore, before going into the script itself, an overview of the
folder structure and the script’s sections will be provided in the
following. The discussion of individual template components will refer
back to these sections for orientation within the script. There will
also be some brief introductory remarks on jsPsych. A more thorough
introduction is provided on the
jspsych website .
A brief note on backslashes and line breaks: Throughout
the template script as well as this document, larger chunks of html code
are frequently broken into multiple lines for visual cohesion. This is
done by adding a backslash at the end of one line’s code before
continuing the code in the line below. Two things should be noted about
this:
- The backslashes only enable line breaks in the code, they do not
produce line breaks in the output text.
- An empty line between multiple lines of html code can cause the code
not to work. Therefore, when deleting parts of a chunk of html code,
make sure not to produce empty lines in the process. If you want to
include an empty line between parts of your html code, you can add a
backslash in the empty line, as is done here
here.
jsPsych
jsPsych is a JavaScript library for creating browser-based experiments.
JavaScript is commonly used to add interactive and dynamic elements to
HTML documents, and the same logic applies to jsPsych: It is used to
create an experiment in the form of an interactive and dynamic HTML
document. jsPsych elements are incorporated into a document via specific
plugins, which are referenced under the head tag of the document. A
given plugin will enable a specific trial, which can present a certain
type of stimulus (e.g. visual or auditory) and record a specific
behavioral response to that stimulus (e.g. clicking on a button or
pressing a key).
For example, importing the image-button-response plugin into your
document will enable
a trial of the type jsPsychImageButtonResponse. You can use
this trial to present visual stimuli and elicit a button response to
them.
<head>
<title>Experiment</title>
<script src="jsPsych_resources/plugin-image-button-response.js"></script>
</head>
var generic_image_button_response_trial = {
type: jsPsychImageButtonResponse,
stimulus: // the image you want to present
stimulus_height: 500,
stimulus_width: 500,
choices: // your response options
button_html: // the buttons displaying your response options
...}
All trials currently defined in the template are covered by the plugins
imported into the script. Specific trial types will be explained in more
detail throughout the document.
Folder Structure
The folder contains the following files and sub-folders:
experiment_template.js: The script containing the
experiment and survey templates. The script makes direct use of all
files and folders listed below except for the R script for stimulus
generation.
stimuli.js: A .js file containing the stimulus sources
for all experiment scenarios. It contains several arrays consisting of
individual stimulus object. These arrays are referenced as the
respective stimulus source in the experiment scenarios. The file is
imported into the script in the Imports and Metadata section
(see below). This is crucial since otherwise, the stimulus references in
the individual experiments won’t work.
<head>
<title>Experiment</title>
<script src='stimuli.js'type="text/javascript"></script>
added_style.css: A .css file providing additional
formatting and visual elements. The elements and classes defined in this
file govern the visual properties of many of the script’s elements,
including the display area, the cursor-orientation point and the visual
stimuli of several experiments. The file is imported into the script in
the Imports and Metadata section (see below).
<head>
<title>Experiment</title>
<link rel="stylesheet" href="added_style.css" />
jsPsych_resources: A folder containing all source files
necessary to run the code of the template script. Among these are a
jsPsych source file, all plugins used in the script, the mouse-tracking
extension, and a standard .css file for jsPsych. The contents of this
folder are imported into the script in the Imports and Metadata
section.
pictures: A folder containing several .png files which
function as visual stimuli in scenarios 1 and 3. The path towards these
files is referenced in the stimulus objects contained in the
stimuli.js file.
sounds: A folder containing several .mp3 files which
function as auditory stimuli in scenario 2. The path towards these files
is referenced in the stimulus objects contained in the
stimuli.js file.
instructions: A folder with image files used in the
instruction element of the template. The folder also contains
the PowerPoint presentation with which the images were created. If you
want to display instructional text via image files, you can use the
slides in this presentation as templates.
audioicon: A .png file displaying an audio icon. The
image is displayed during the presentation of auditory stimuli in
scenario 2.
response_image: A .png file displaying the emotional
response map used in scenario 2.
create_stimulus_objects.R: An R script which will
generate and export the stimulus arrays used for scenarios 1 and 2. The
script can be used to generate the stimulus objects for your experiment
automatically.
Template Structure
The template script is organized into the following main sections, which
appear in the following order of mention:
Imports and Metadata: This section specifies all
sources external to the script. It imports all jsPsych plugins necessary
to run the experiment components as currently defined. Further plugins
can be added here if they are needed. It also imports the
stimuli.js file containing the stimulus arrays as well as the
added_style.css file, as was shown above. All of this is done
under the head tag of the document. Under the body tag
below, the display area is referenced, which is the area on screen
within which all visual elements are displayed.
Global Settings: This section contains several
macro-level parameters which adjust the output of the script. Among
these are: The specific scenario to be executed, the height and width of
the display area, the position of the cursor-orientation point, and the
use of specific stimulus lists. These components will be explained in
more detail below, but they can all be adjusted by changing a single
value in the global settings. Below is an overview of the parameters in
this section.
main_sequence_choice = // Choice between scenarios 1, 2 and 3
display_area_setting = [,] //Display area size in pixels.
lists = [, ..., n] // Number of lists in your experiment
random = _.sample(lists) // draws a random sample (n=1) from the lists array
list_choice = //Variable for list assignment
audioicon = //Path to the audio icon used in scenario 2
initial_mouse_position = [,] // Distance of orientation point with respect to the display area.
sampling_time_mouse_tracking = //temporal resolution (milliseconds) of mouse-movement tracking.
This section also contains the code which will initialize jsPsych in the
script and add the mouse-tracking extension. It also conains a variable
which will generate a random subject ID in each experiment session and
add it to the output file.
General Components: This section defines elements which
are not specific to any experiment, but are either featured in all of
them (such as blank pages and cursor orientation), or are external to
the experiment sequence itself (such as instructions and pre- or
post-experiment surveys).
Experiment Scenarios 1-3: Each experiment has its own
section defining its specific components and timeline. These will be
explained in detail below.
Main Sequence and Timeline: This section contains the
global timeline of the experiment session. Any element to be featured in
a session is included in this timeline. The section also contains a
variable called main_sequence, which consists of one of the
three experiment scenarios (see below).
Data Processing and Storage: This section contains
several functions which enable the processing and storage of the data
generated in the experiment. One of these functions unpacks the recorded
cursor coordinates and their associated time points into individual
columns in the output file. This function is applied in every experiment
scenario (see below). The other functions enable saving the data on your
device or uploading them to a server.
Global Timeline and Main Sequence
Timeline
Running an experiment in jsPsych means running a timeline. The timeline
is an array which contains all elements to be executed in their intended
order, so this is where you specify the overall structure of your
experiment session .
Below is a minimal timeline. Upon execution, it will do the following:
1. Generate a start screen from which participants can initiate the
experiment sequence, 2. Run the experiment sequence and once this
sequence is finished 3. Tell participants that they can now end the
experiment by clicking on a button. Note that the timeline will be run
via the command below it.
var timeline = [start_experiment, main_sequence, debrief];
jsPsych.run(timeline);
A more elaborate timeline, which more accurately reflects what your
experiment may look like in the end, is shown below.
var timeline = [preload_media, fullscreen_mode, browser_check, consent, pretest, instruction, start_experiment, main_sequence, task_finish, posttest, debrief];
jsPsych.run(timeline);
Compared to the minimal timeline, this one includes many standard
procedures of a (browser-based) experiment session: For example, it
pre-loads all stimulus files prior to their presentation and enables
full-screen mode. There are also consent and instruction pages before
the experiment sequence is launched and the experiment is preceded and
followed by survey elements.
In short: Any specific step you want to include in the flow of your
experiment session needs to appear in the timeline.
Main Sequence
All of the elements which appear in the timeline above are defined in
the template script and will be explained in this document, but before
that, some remarks on the main_sequence element are in order.
This element is a variable representing the specific experiment scenario
(1-3) to be run. It therefore always refers to one of three
additional timelines. As you will see below, each experiment
scenario has its own timeline specifying the sequence of elements which
make it up. Which of these timelines is picked up by the
main_sequence element is determined in the following way:
In the Global_Settings section, you find a parameter called
main_sequence_choice, which accepts as input the numbers 1, 2
or 3. Based on that input, a function in the Main Sequence and
Timeline section will return one of the three scenario timelines
and hand it over to the main_sequence variable. So, while the
overall timeline of the experiment session is manually determined in the
Main Sequence and Timeline section, the specific scenario
choice is manually determined in the Global Settings section.
main_sequence_choice = 3 // returns scenario 3 timeline as main sequence
Common Properties of all Scenarios
Stimulus Referencing
All three experiment scenarios consist of jsPsych elements used to
display a specific type of stimulus (e.g. a picture or sound) and elicit
a specific type of response (e.g. clicking on a button or pressing a
key). These elements are then referenced in a timeline specific to the
scenario, which additionally includes surrounding elements which make up
the structure of a trial (e.g. cursor orientation, a preview screen, or
simply a blank screen for some time). The scenario timeline therefore
determines what a single experimental trial will look like.
Crucially, the scenario timeline has an additional parameter specifying
a timeline variable. In this template, this variable
corresponds to one of the stimulus arrays in the stimuli.js
file. By referencing an array from this file as a timeline variable, two
things become possible:
1. The elements which make up an experiment scenario
can reference the contents of the arrays in stimuli.js as their
stimulus material.
2. The timeline which represents an experimental trial
will not run once, but will loop through the stimulus array for as many
times as there are stimulus objects in this array.
This principle is demonstrated in the
following by looking at some of the components of scenario 1. Below you
can see the timeline of scenario 1.
var scenario1 = {
timeline: [blank_page, position_cursor, blank_page, labels_preview, label_choice],
timeline_variables: stimulus_set_scenario1,
randomize_order: true,
}
The parameter timeline_variables references an object of the
name stimulus_set_scenario1. This object is an array in the
stimulus.js file and it looks like this
:
var stimulus_set_scenario1 = [
{itemID:1, list:'a', condition: 'control', picture:'chair_bw.png',
picture_path: 'pictures/chair_bw.png', left: 'chair', right: 'bench'},
{itemID:2, list:'b', condition: 'control', picture:'car_bw.png',
picture_path: 'pictures/car_bw.png', left: 'bus', right: 'car'},
{itemID:3, list:'c', condition: 'control', picture:'pot_bw.png',
picture_path: 'pictures/pot_bw.png', left: 'pan', right: 'pot'},
...]
As you can see, the array contains objects of identical structure but
different content. Of particular interest here are the following
variables:
picture_path: Points to a specific .png file in the
pictures folder.
left: Specifies the label option displayed on the top
left of the picture.
right: Specifies the label option displayed on the top
right of the picture.
The variables above are referenced by the label_choice element
used in scenario 1. This is shown below .
The label_choice element is an image-button-response trial,
which will display an image and elicit a response to that image in the
form of a button choice.
var label_choice = {
type: jsPsychImageButtonResponse,
stimulus: jsPsych.timelineVariable('picture_path'),
stimulus_height: 500,
stimulus_width: 500,
choices: [jsPsych.timelineVariable('left'), jsPsych.timelineVariable('right')],
button_html:
['<button class="jspsych-btn" style="position:absolute; left:80px; top: 80px; \
font-size: 22px" >%choice% </button>',
'<button class="jspsych-btn" style ="position:absolute; right:80px; top: 80px; \
font-size: 22px" >%choice% </button>'],
response_ends_trial: true,
render_on_canvas: false,
...}
The stimulus parameter of this trial references the
picture_path variable from the stimulus_set_scenario1
array, so the image shown in a given trial will correspond to the image
pointed to by this variable in a given stimulus object. Note that for
this type of reference, the function jsPsych.timelineVariable()
needs to be used.
In the same manner, the choices parameter of the trial
references the variables left and right from the
stimulus array. The button_html parameter below generates the
two buttons displayed in the trial, and their content is linked to the
choices parameter above. Therefore, the contents of the two
buttons will correspond to the contents of the left and
right variables in a given stimulus object. For the first
object in the stimulus array, the trial will therefore look like the
image below .
var stimulus_set_scenario1 = [
{itemID:1, list:'a', condition: 'control', picture:'chair_bw.png',
picture_path: 'pictures/chair_bw.png', left: 'chair', right: 'bench'},
...]

In short: Any content you want displayed during a trial must be found as
a variable in the corresponding stimulus array. For individual files,
this variable needs to specify the path towards their location.
List Assignment
If you want all stimuli from the corresponding stimulus array to be
presented in the experiment, simply reference the stimulus array as the
timeline variable of a given scenario, as shown in the
previous section. Additionally, all
experiments include the option of presenting only stimuli from a
specific list. This option is currently the default for scenario 3 only,
but it can be enabled for all experiments in the manner described in the
following.
Each stimulus array includes a list variable with either a, b
or c as its content. From this variable, sub-arrays containing only
stimuli from a given list are created in the stimuli.js file.
This is shown for the stimulus array of scenario 1 below.
var one_list_a = Array.from(stimulus_set_scenario1). filter(item => item.list === 'a')
var one_list_b = Array.from(stimulus_set_scenario1). filter(item => item.list === 'b')
var one_list_c = Array.from(stimulus_set_scenario1). filter(item => item.list === 'c')
Each experiment section contains its own
function listAssign() , which gets its input from
the list_choice parameter in the Global
Settings section. Based on this input, the function will return one
of the three list-specific sub-arrays in stimuli.js.
To enable list-specific stimulus presentation, you need to reference
listAssign(list_choice) as the timeline variable in a given
scenario. The timeline setting is shown for scenario 1 below. Note that
the function is labelled for its specific scenario. This is the case for
all scenarios, so the corresponding functions for scenarios 2 and 3 are
listAssign2() and listAssign3() respectively.
var scenario1 = {
timeline: [blank_page, position_cursor, blank_page, labels_preview, label_choice],
timeline_variables: listAssign1 (list_choice),
randomize_order: true,
}
When list-specific presentation is enabled, you have two basic options
for list assignment:
1. Manually choosing a specific list: You can do this
via the list_choice parameter in the Global Settings
section. There, enter either 1, 2 or 3, from which the
listAssign() function will return either list a, b or c
respectively.
list_choice = 1 //returns list a
2. Random list assignment: To do this, enter ‘random’
as input for the list_choice parameter in the Global
Settings section. This will draw a random sample from the
lists array in the same section.
lists = [1,2,3] // each number is a list in your experiment
random = _.sample(lists) // draws a random sample (n=1) from the lists array above
list_choice = random // takes the random sample as list choice
If your experiment design includes more or less than three lists, you
will have to adjust the number of list-specific arrays in the stimulus
source and the corresponding listAssign() function for the new
number of lists. For random assignment, you will also have to adjust the
lists array from which the random variable will
sample. For example, five lists would require an array of the form
[1,2,3,4,5]. The lists array can be found in the Global
Settings section. As mentioned above, each experiment section has
its own listAssign() function.
Adding Data
While a scenario timeline contains several
trials, we are often interested in the data produced in one trial
specifically, namely the one where the behavioral response of interest
is elicited. The data generated automatically in jsPsych trials usually
amounts to reaction time and the response option chosen by a participant
(see this section for an explanation of this
variable). In most cases, this is not sufficient for the purposes of our
analysis. For example, we may want to know which condition of our
experiment design this trial belongs to, or which specific stimuli were
displayed in the trial.
For scenario 1, the trial most relevant in terms of the data generated
is the label_choice trial shown
previously. In order to add more information to this trial, we can
refer to the stimulus array for
scenario 1. The array contains a condition variable, an
item ID as well as a picture variable. In the code below, this
(and more) is added to the data generated in the label_choice
trial.
var label_choice = {
type: jsPsychImageButtonResponse,
stimulus: jsPsych.timelineVariable('picture_path'),
...
data:{
component: 'experiment',
itemID:jsPsych.timelineVariable('itemID'),
list:jsPsych.timelineVariable('list'),
condition: jsPsych.timelineVariable('condition'),
picture: jsPsych.timelineVariable('picture'),
left: jsPsych.timelineVariable('left'),
right: jsPsych.timelineVariable('right'),},
...
}
Every jsPsych trial has a data property to which information
can be added, as is done above. All data added there will be included in
the results file. Just as in stimulus referencing, in order to point
towards the data we want to include, we have to use the function
jsPsych.timelineVariable(), since the additional information
also originates from the stimulus array referenced as the scenario’s
timeline variable.
You can also add data not originating from the stimulus source. For
example, above we add a component variable with the string
‘experiment’ as its value. Since the output file of an experiment
session will include all data generated in any jsPsych trial, this
variable will later help us identify the rows in the results file which
are relevant to our analysis.
Below you can see what the trial’s output will look like once we
added the additional data.

Mouse Tracking
For a guide on how to interpret the cursor coordinates recorded via the
mouse-tracking extension, go here .
Adding and Tracking
Mouse tracking is currently enabled in all experiment scenarios. It is
essential for scenario 2, where participants respond by positioning the
cursor inside an emotional response map, but it may be used in the other
scenarios as a more fine grained window into participant’s decision
process.
The mouse-tracking extension is first imported in the Imports and
Metadata section, and then added when jsPsych is initialized in the
Global_Settings section. This section includes the parameter
sampling_time_mouse_tracking, which determines the sampling
time of the tracking process.
sampling_time_mouse_tracking = 500 //temporal resolution of mouse-movement tracking in ms
Generally, the cursor position is only recorded while the cursor is in
motion (and when a mouse click occurs). The sampling time determines how
fine grained the recording of the cursor trajectory will be. The current
setting is 500, so while in motion, the cursor is tracked every 500
milliseconds. You can up- and downscale this parameter to suit your
specific purposes.
To include mouse tracking data as a variable in a given experiment, the
extension needs to be added specifically to the critical trial in the
scenario timeline. This is shown in the following for scenario 2. The
scenario timeline is displayed below.
var scenario2 = {
timeline: [blank_page, position_cursor, blank_page, audio_stimulus, blank_page,
mouse_response],
...}
We want to include mouse tracking in the final trial of this timeline,
where participants indicate their emotional response along the map
displayed in the trial. This is done in the code below, which shows the
relevant part of the mouse_response trial.
var mouse_response = {
type: jsPsychHtmlKeyboardResponse,
stimulus: function (){
var html = '<div id="image_container"><img src="response_image.jpeg"></img></div>'
return html },
...
extensions: [
{type: jsPsychExtensionMouseTracking,
params: {events: ['mousemove','mousedown'] //user can choose between the two
}}],
...
on_finish: function(data) {
processMouseTrackingData(data.mouse_tracking_data)
},
}
The stimulus parameter references the image file of the
response map, which will cover the entire display area. Under the
extensions parameter, the mouse-tracking extension is
referenced. Two types of cursor-related event are specified for tracking
in the extension’s parameter settings:
mousemove: The cursor position will be tracked while in
motion (with the sampling rate specified in the Global Settings
section).
mousedown: Corresponds to a mouse click.
Recording the position of a mouse click enables us to determine a
participant’s ultimate response in the trial above, since a mouse click
will end the trial (this is not shown in the code above). By adding the
extension to a given trial, the mouse-tracking data will be added to
that trial’s data property, which was the subject of the
previous section.
Processing
In the on_finish parameter of the above trial, a function is
added which will process the data generated by the mouse-tracking
extension so that they assume a certain format:
For each recording instance, the mouse-tracking extension specifies an
x- and y coordinate for the cursor (in pixels), and a time point in
reference to the trial’s onset (t). In the default format, these 3
values form an object representing one recording instance, and the
entire data appear in one array containing each of those objects. This
can be seen in the image below, which shows the unprocessed
mouse-tracking data in a trial’s output.

The function above will unpack each object in this array, so that each
x-, y- ant t measure from a given recording instance appear as a
separate variable in the output file. The result of this functiong in
the trial’s output is shown below.

The function is defined in the Data Processing and Storage
section of the template script. If you want the mouse-tracking data
unpacked, you need to include the function in the critical trial, as
above. Note that the original mouse-tracking data, which is the argument
of the function, is accessed via the trial’s data property (see
previous section).
Display Area
The display area is a predefined area on the
screen whithin which all visual elements are displayed. It ensures that
the arrangement of visual stimuli is consistent across different screen
sizes. The position of the area is defined in the
added_style.css file. In its current settings, it appears as a
quadrangle 100px below the top of the screen in the horizontal center.
You can change this position in the margin parameter of the
corresponding element in the .css file. If you want the area’s
boundaries to be invisible, you can change the color of the
border parameter to white in the .css file. The
corresponding .css element is shown below.
#display_area {
display: flex;
position:relative;
width:800px;
height: 600px;
margin: 100px auto;
border: 2px solid grey;
}
The display area is referenced as the document’s body in the Imports
and Metadata section of the script. This will make all visual
elements appear inside the area by default. It is also referenced as the
display element when jsPsych is initialized in the Global
Settings section. Thereby, all visual stimuli used in a given
jsPsych element will be positioned in reference to the display area’s
boundaries. For example, positioning a response button vertically via
‘top:80px’ now means that it is located 80px below the top of the
display area.
While the position and boundary visibility of the display area can be
changed in the added_style.css file (see above), the size of
the area can be changed by the display_area_setting parameter
in the Global Settings section. The first number in this
parameter determines the area’s width, the second number determines its
height (both in pixels). Currently, the area is 800 pixels wide and 600
high wide.
display_area_setting = [800,600]
Cursor Orientation
To control for the initial cursor position at the start of an
experimental trial, each scenario’s timeline includes the same
cursor-orientation trial prior to stimulus presentation. It presents a
black circle in a predefined position in the display area. Moving the
cursor into the circle will end the orientation trial and initiate the
next element in the scenario timeline. How this is achieved will be
explained in the following.
The visual properties of the orientation point are defined in the
added_style.css file, where you can change its size, color and
shape.
#cursor_position {
width: 50px;
height: 50px;
border-radius: 50%;
background-color: black;
}
The position of the orientation point is controlled via the
initial_mouse_position parameter in the
Global_Settings section. The first value in the parameter
determines the vertical position, the second value determines the
horizontal position, both in percent in reference to the display-area
boundaries. By default, both positions refer to the center of the
display area, which corresponds roughly to [47,47]. Changing the first
value to, say, 90, will make the orientation point appear at the bottom
of the display area, but still in the horizontal center.
initial_mouse_position = [47,47]//default setting - centered vertically and horizontally
The orientation trial is defined as the position_cursor
element in the General_Components section of the script. The
code is displayed below.
var position_cursor = {
type: jsPsychHtmlKeyboardResponse,
stimulus: function () {
var html =
`<div id="cursor_position" class="cursor_position"
style="position:absolute;
top:${initial_mouse_position[0]}%;
left:${initial_mouse_position[1]}%;">
</div>`
return html },
choices: "NO_KEYS",
on_load: function () {
var position_cursor = document.getElementById('cursor_position');
position_cursor.addEventListener('mouseover', function () {
jsPsych.finishTrial(); }); }, };
Note that this is originally a keyboard-response trial (see the
type parameter), though no keyboard response is required for
our purposes. Therefore, the choices parameter of the trial has
the option NO_KEYS as its input. Three important things happen
in the code displayed above:
1. The stimulus parameter references the
cursor_position element from the .css file displayed in the
beginning of this section, which will give the orientation point the
visual properties defined in the .css file.
2. The style property of this element
references the values of the initial_mouse_position parameter
shown previously (note that this reference is followed by a percent
symbol, determining how the numbers are interpreted).
3. The on_load parameter defines a conditional
event in reference to the orientation point. If the cursor enters the
area corresponding to the orientation point (this is what the
mouseover event encodes), the orientation trial will end. If
you want to change the conditions under which the trial ends to, say, a
clicking event inside the orientation point, you can simply change the
event referenced here to mouseup.
Blank Pages and Hidden Cursor
The blank page element is pretty much what it says: A blank screen
presented for a predefined amount of time before the next element in the
scenario timeline is initiated. It is meant to make the transition from
one element to another less abrupt. For example, it gives participants a
minimum amount of time to prepare for stimulus presentation after
progressing from the cursor-orientation trial. Each scenario makes use
of the blank page element at several points throughout an experimental
trial.
The blank_page element is defined in the General
Components section of the template script, the corresponding code
is shown below.
var blank_page = {
type: jsPsychHtmlKeyboardResponse,
stimulus: '',
choices: "NO_KEYS",
prompt: enable_hidden_cursor(),
css_classes:['hidden-cursor'],
trial_duration:500
}
As with the cursor-orientation trial, this is originally a
keyboard-response trial, but we are not interested in a keyboard
response. Therefore, the NO_KEYS option is employed again.
As you can see, the stimulus parameter of the trial contains
nothing, giving us the blank screen. The presentation duration is
determined in milliseconds by the trial_duration parameter.
Currently, the blank screen is presented for 500ms. You can adjust this
duration for your purposes. If you need several blank pages of different
durations, you may simply copy the code as many times as you need, give
the trials unique names (e.g. blank_page1, blank_page2
etc.) and adjust the duration for each of them according to your
purposes.
Note that for the duration of the trial, the cursor will not be visible.
This is done by 1. Adding the prompt enable_hidden_cursor() and
2. Referencing the hidden_cursor class attribute from the
added_style.css file, which simply states that the cursor
should not be visible in an element to which it is attributed. By
prompting the variable enable_hidden_cursor, the
hidden_cursor attribute is applied to the entire screen. This
combination is also used in other trials and is useful whenever you want
to enforce that participants won’t move the cursor at a given point in
time (they can of course still do that when the cursor is not visible,
but are probably less likely to do so).
Scenario 1
Scenario 1 is a simple categorization task, where an image of an object
is displayed towards the bottom center of the display area, together
with two buttons representing label choices displayed above it. Most
trials in this scenario are fillers where the label choice is trivial.
Five trials are the critical ones, where more or less prototypical
cups/bowls are presented together with these two labeling options.
The code block defining scenario 1 is embedded in the function
Scenario1(). The code will be executed only if the
main_sequence_choice parameter in the global settings
section has the value 1.
function Scenario1 () {
if (main_sequence_choice === 1) {
// code block for scenario 1
return scenario1
}
}
The function above will return the variable scenario1 defined
in the scenario’s code block. This variable contains the scenario
timeline, which can be seen below. The stimulus material originates from
the stimulus_set_scenario1 array in the stimuli.js
file. Randomization of presentation order is enabled in the current
settings.
var scenario1 = {
timeline: [blank_page, position_cursor, blank_page, labels_preview, label_choice],
timeline_variables: stimulus_set_scenario1,
randomize_order: true,
}
The experiment will start with the sequence blank_page -
position_cursor - blank_page before the scenario-specific elements
are run. Including a blank page in the beginning of the trial will make
the transition from one trial to the next appear more smooth.
Preview
The labels_preview element is defined in the Scenario 1
section of the script. It presents the labeling options for some
time before the image appears. This may be important if you are
interested in the reaction time for the label_choice trial. By
giving participants time to pre-process the labels, the reaction time in
the subsequent trial will more accurately reflect the decision process.
The code for the preview element is displayed below.
var labels_preview = {
type: jsPsychImageButtonResponse,
choices: [jsPsych.timelineVariable('left'), jsPsych.timelineVariable('right')],
button_html:
['<button class="jspsych-btn" style="position:absolute; left:80px; top: 80px; \
font-size: 22px" >%choice% </button>',
'<button class="jspsych-btn" style ="position:absolute; right:80px; top: 80px; \
font-size: 22px" >%choice% </button>'],
prompt: enable_hidden_cursor(),
css_classes:['hidden-cursor'],
trial_duration:700
}
Even though this is an image-button-response trial, the
stimulus parameter is missing, since we only need the buttons
(this will produce a warning when debugging which you can safely
ignore). The choice and button_html parameters in this
trial are identical to the subsequent label_choice trial:
The choice_parameter references the left and
right variables from the stimulus array. The
button_html parameter creates two buttons. Both buttons are
positioned 80px below the top of the display area, and 80px away from
its left or right boundary. For both buttons, their content is linked to
the choices parameter through the %choice% element.
During the preview trial, the cursor is hidden, minimizing the chance of
prior cursor movement. In its current setting, the button preview will
last 700ms, after which the label_choice trial is initiated.
Label Choice
The label_choice trial is defined in the Scenario1
section of the script. In terms of visual presentation, the only
difference between this trial and the preview trial is the presence of
the image to be responded to. From a participant’s perspective, they are
looking at the same page as before, only that an image was added. Apart
from adding the image reference in the stimulus parameter, the
initial code of the two trials is therefore pretty similar, with the
addition of specifying that a response will end the trial.
var label_choice = {
type: jsPsychImageButtonResponse,
stimulus: jsPsych.timelineVariable('picture_path'),
stimulus_height: 500,
stimulus_width: 500,
choices: [jsPsych.timelineVariable('left'), jsPsych.timelineVariable('right')],
button_html:
['<button class="jspsych-btn" style="position:absolute; left:80px; top: 80px; \
font-size: 22px" >%choice% </button>',
'<button class="jspsych-btn" style ="position:absolute; right:80px; top: 80px; \
font-size: 22px" >%choice% </button>'],
response_ends_trial: true,
...}
Note that the image size can be adjusted directly in the trial’s code
(see above). The image position is governed by an external element in
the added_style.css file. In the current settings, the image is
displayed in the bottom center of the display area. You can change this
setting in the corresponding element in the .css file.
#jspsych-image-button-response-stimulus{
object-fit: none;
object-position: center bottom;}
An example screen of the label_choice trial can be seen
here .
Since this is our critical trial in terms of data collection, more is
going on in the background: Mouse tracking is added, additional
information is added to the trial’s data property, and the
function for unpacking the mouse-tracking data is included, giving us
the rest of the trial’s code.
var label_choice = {
...
extensions: [
{type: jsPsychExtensionMouseTracking,
params: {events: ['mousemove','mousedown']
}
}
],
data:{
component: 'experiment',
itemID:jsPsych.timelineVariable('itemID'),
list:jsPsych.timelineVariable('list'),
condition: jsPsych.timelineVariable('condition'),
picture: jsPsych.timelineVariable('picture'),
left: jsPsych.timelineVariable('left'),
right: jsPsych.timelineVariable('right'),
},
on_finish: function(data) {
processMouseTrackingData(data.mouse_tracking_data);
},
};
How to Modify
Suppose we wanted to flip the modalities of our categorization task such
that a word is displayed, and one of two pictures which more accurately
matches the word must be chosen. We could do this roughly in the
following way:
1. Our stimulus array needs to be adjusted according to
our new design. Specifically, we need a variable determining the word to
be displayed, and two variables pointing towards our response pictures.
For a single stimulus object in our array, this could look like below.
var stimulus_set_scenario1 = [
{itemID:1, list:'a', condition: 'control', word: 'hat',
left: 'hat', left_picture_path: 'pictures/hat_bw.png',
right: 'crown', right_picture_path: 'pictures/crown_bw.png'}];
We now have a word variable specifying which word will be
displayed, and two variables with a path to the left and right picture
respectively. We have also kept our original left and
right variables for easier reference later.
2. Next, our label_choice trial needs to be
adjusted (we skip over the preview trial for brevity’s sake). Instead of
an image-button-response-trial, we now need an html-button-response
trial, whose stimulus is a text element rather than an image. Within
this trial, we then reference our new variables. We also give the trial
a more appropriate name, since this is a picture choice, not a label
choice.
var picture_choice = {
type: jsPsychHtmlButtonResponse,
stimulus: function (){ return (
'<p style = "font-size:34px; position:absolute; left:47%; top:65%">'
+jsPsych.timelineVariable('word')
+'</p>'
)},
choices: [jsPsych.timelineVariable('left_picture_path'),
jsPsych.timelineVariable('right_picture_path')],
button_html:
['<button class="jspsych-btn" style="position:absolute; left:80px; top: 80px"> \
<img src="%choice%" style="width: 150px; height: 150px;"/></button>',
'<button class="jspsych-btn" style ="position:absolute; right:80px; top: 80px"> \
<img src="%choice%" style="width: 150px; height: 150px;"/></button>'],
response_ends_trial: true,
...}
Above, we have re-labeled our trial and re-specified its type as
jsPsychHtmlButtonResponse. The stimulus parameter now
references our new word variable. This reference is embedded in
some html formatting, which allows us to adjust the size and position of
the word. In order to do this, we need to embed both the html formatting
and the stimulus reference inside a function.
The choice parameter now references our new
picture_path variables. And the buttons generated below will
take this reference as input accordingly. Also, we have re-sized the
buttons to appropriately display the images. As a result of our
modification, a trial will now look like below.

This is just one way in which the scenario can be modified. Another idea
might be to keep the change of modalities above, but to present words as
auditory rather than visual stimuli. This would entail corresponding
audio files, a variable in the stimulus array pointing to those files,
and making the decision trial an audio-button-response trial. This
trial’s stimulus parameter could then reference the new
audio_path variable for stimulus presentation.
Scenario 2
Scenario 2 is a two-dimensional rating task, where participants hear a
word and subsequently indicate their emotional response along two
dimensions (valency and arousal) in an associative response map.
Compared to the other scenarios, mouse tracking is more essential here,
since the cursor position inside the response map corresponds to a pair
of values in a two-dimensional grid, so a mouse click inside the map
reflects participant’s ultimate rating along that grid.
The code block defining scenario 2 is embedded in the function
Scenario2(). The code will be executed only if the
main_sequence_choice parameter in the global settings
section has the value 2.
function Scenario2 () {
if (main_sequence_choice === 2) {
// code block for scenario 2
return scenario2
}
}
The function above will return the variable scenario2 defined
in the scenario’s code block. This variable contains the scenario
timeline, which can be seen below. The stimulus material originates from
the stimulus_set_scenario2 array in the stimuli.js
file. Randomization of presentation order is enabled in the current
settings.
var scenario2 = {
timeline: [blank_page, audio_stimulus, blank_page, position_cursor, blank_page,
mouse_response],
timeline_variables: stimulus_set_scenario2,
randomize_order: true,
}
The experiment sequence starts with the presentation of the audio
stimulus, which is preceded and followed by a 500ms blank page. After
this, the cursor-orientation trial is launched, which triggers the onset
of the response map after another 500ms blank page.
Audio Stimulus
The auditory stimulus is presented via the audio-button-response trial
shown below. The trial is defined in the Scenario 2 section of
the script. The stimulus parameter of the trial references the
audio_path variable from the corresponding stimulus array to
retrieve the word to be presented.
var audio_stimulus = {
type: jsPsychAudioButtonResponse,
stimulus: jsPsych.timelineVariable('audio_path'),
choices: [audioicon],
button_html: '<button class="jspsych-btn" id = "jspsych-audio-button-response-button"> \
<img src="%choice%" style="width: 100px; height: 100px;"/></button>',
trial_duration: 2500,
//trial_ends_after_audio: true,
response_ends_trial: false,
prompt: enable_hidden_cursor(),
css_classes:['hidden-cursor']
};
The auditory stimulus is accompanied by an audio icon. The icon image
file is handed over to the variable audioicon in the
Global Settings section. This variable is referenced in the
choice_parameter above, and a button containing the image is
generated in the button_html parameter. In order for the image
to look natural (i.e not like a button), the button appearance is
externally controlled by an element in the added_style.css
file, and this element is referenced as the button’s ID above.
To prevent an accidental mouse click on the button from prematurely
ending the trial, the parameter response_ends_trial is set to
false. Also, the cursor is not visible during the trial. The
trial offers two options as to its presentation duration: It either ends
once the audio file is finished, or it ends after a pre-specified time
period. In the above settings, the latter is activated. To change this,
you can simply delete the back slashes before the
trial_ends_after_audio parameter and add them before the
trial_duration parameter instead.
Mouse Response
The mouse_response trial is defined in the Scenario 2
section of the script. It is originally a keyboard-response trial. Since
no keyboard response is required, this response option is disabled via
the NO KEYS argument (see below).
var mouse_response = {
type: jsPsychHtmlKeyboardResponse,
stimulus: function (){
var html = '<div id="image_container">\
<img src="response_image.jpeg"></img></div>'
return html
},
choices: "NO_KEYS",
//trial_duration: 2000,
on_load: function () {
var target = document.getElementById('image_container');
if (trial_auto ===true) {
target.addEventListener('mouseup', function () {
jsPsych.finishTrial();
});
}},
...
}
In the stimulus parameter, the image showing the response map
is placed inside an element from the added_style.css file
called image_container. This is done in order for the image to
extend over the entire display area.
To make the trial respond to a mouse click (rather than a key press, as
intended by the trial type), a function is added in the on_load
parameter. There, a conditional event is added in reference to the
image_container element, which is spatially congruous with the
response map and the display area. If a mouse click (= mouseup)
is registered inside the element, the trial is ended.
The code includes the additional option of adding an upper limit to the
trial duration. This is currently disabled (see above), but may be
activated by simply removing the back slashes before the
trial_duration parameter.
Since this is the main trial for data gathering in this scenario,
several further properties are included, as can be seen in the second
part of the trial’s code below: The mouse-tracking extension is added,
several variables from the stimulus source such as the item ID and the
experimental list are added to the data property, and the
unpacking function for the mouse tracking data is added in the
on_finish parameter.
var mouse_response = {
...
extensions: [
{type: jsPsychExtensionMouseTracking,
params: {events: ['mousemove','mousedown']
}
}
],
data: {
itemID:jsPsych.timelineVariable('itemID'),
list:jsPsych.timelineVariable('list'),
audio_stimulus: jsPsych.timelineVariable('audio'),
},
on_finish: function(data) {
processMouseTrackingData(data.mouse_tracking_data)
},
}
How to Modify
One way to expand on the setup could be to display different images
along with the auditory stimuli. We may thereby investigate how visually
and auditorily presented concepts interact in participant’s emotional
response.
Suppose we wanted to see whether participants’ response to an
emotionally charged image differs when this image is combined with
semantically related words which have either strong, mild or no negative
connotations of the same nature. This would yield three conditions in
which the same image is combined with different words. A corresponding
stimulus array may look like the following.
var stimulus_set = [
{itemID: 1, connotation: 'neutral', image: 'tank', picture_path: 'pictures/tank.png',
word: 'vehicle', audio_path: 'sounds/vehicle.mp3'},
{itemID: 2, connotation: 'strong', image: 'tank', picture_path: 'pictures/tank.png',
word: 'war', audio_path: 'sounds/war.mp3'},
{itemID: 3, connotation: 'mild', image: 'tank', picture_path: 'pictures/tank.png',
word: 'conflict', audio_path: 'sounds/conflict.mp3'},
...
]
In the array above, three trials are defined in each of which an image
of a tank is combined with words which have strong (war), mild
(conflict) or no negative connotations (vehicle). In a real experiment,
each of these words would further be combined with the same neutral
image (e.g. of a car) in order to get a baseline reaction to the words
themselves.
The good thing about this modification of scenario 2 is that apart from
the stimulus array, everything else is in place. All we need to do is
change the reference of the choice parameter in the
audio_stimulus trial, which currently points to the icon image.
We now reference our new picture_path variable instead. Since
the button element is already designed to display an image, we can leave
it the way it was. Since we are still interested in participants’
emotional response, we can also leave the subsequent rating trial in
place.
var audio_stimulus = {
type: jsPsychAudioButtonResponse,
stimulus: jsPsych.timelineVariable('audio_path'),
choices: [jsPsych.timelineVariable('picture_path')],
button_html: '<button class="jspsych-btn" id = "jspsych-audio-button-response-button"> \
<img src="%choice%" style="width: 100px; height: 100px;"/></button>',
...
}
Scenario 3
Scenario 3 is a masked priming experiment, in which participants are
prompted to click on a target image belonging to a certain semantic
category. The prompt is followed by a prime word presented for a very
brief time period before the image screen appears, where the target
image is presented among three distractor images. Prime words are either
identical, semantically related or unrelated to the target image. A
given target image is combined with each prime condition once, and the
experiment is designed for list-specific presentation, such that for a
given target picture, each condition is assigned to a different list.
The code block defining scenario 3 is embedded in the function
Scenario3(). The code will be executed only if the
main_sequence_choice parameter in the global settings
section has the value 3.
function Scenario3 () {
if (main_sequence_choice === 3) {
// code block for scenario 3
return scenario3
}
}
The function above will return the variable scenario3 defined
in the scenario’s code block. This variable contains the scenario
timeline, which can be seen below. The stimulus material originates from
one of three list-specific arrays derived from the
stimulus_set_scenario3 array in the stimuli.js file.
List assignment is governed by the function listAssign3().
Randomization of presentation order is enabled in the current settings.
var scenario3 = {
timeline: [blank_page, position_cursor, blank_page, prompt, prime, target_screen],
timeline_variables: listAssign3(list_choice),
randomize_order: true,
}
The experiment starts with a blank_page - position_cursor -
blank_page sequence. Following this, the search prompt appears,
followed by the masked prime word. After this, the screen displaying the
target image among three distractors is presented.
Prompt and Prime
The search prompt and the prime word are presented in individual trials
which are both defined in the Scenario 3 section of the script.
Since they both involve relatively little and similar code, they are
presented in one section here. Both elements are html-keyboard-response
trials presenting text as their respective stimulus. Since no keyboard
response is required, this response option is disabled in both elements.
The prompt trial’s code and an example of its output are shown
below.
var prompt = {
type: jsPsychHtmlKeyboardResponse,
stimulus: function(){return '<p>click on the </p> \
+++ ' +jsPsych.timelineVariable('prompt')+ ' +++'},
choices: 'NO_KEYS',
prompt: enable_hidden_cursor(),
css_classes:['hidden-cursor'],
response_ends_trial:false,
trial_duration:1000
}

The stimulus parameter of the prompt trial references
a variable of the same name from the corresponding stimulus array. This
variable contains a single word specifying the semantic category of the
target picture. In the above example, this word is ‘animal’. The
reference is preceded by a prompt sentence (‘click on the’) and flanked
by plus signs from both sides. These function as the visual mask for the
following prime word. Note that the cursor is not visible during the
trial. In the current settings, the prompt is presented for 1000ms
before the prime element is launched.
The prime trial’s code and and example of its output are shown
below.
var prime = {
type: jsPsychHtmlKeyboardResponse,
stimulus: function(){return '<p>click on the </p> \
+++ ' +jsPsych.timelineVariable('prime')+ ' +++'},
choices: 'NO_KEYS',
prompt: enable_hidden_cursor(),
css_classes:['hidden-cursor'],
response_ends_trial:false,
trial_duration:40
}

This trial is structurally identical to the preceding one, except that
the stimulus parameter now references the prime
variable from the stimulus array. The variable contains a single word
which is, depending on the condition, identical, semantically related or
unrelated to the target picture. Note that the duration of the
prime trial is very brief (currently only 40ms). For a test
run, you may want to increase the trial duration or enable a keyboard
response ending the trial in order to be able to inspect it.
Target Screen
The target and distractor pictures are presented as buttons in an
html-button-response trial. The trial’s initial code and an example of
its output are shown below.
var target_screen = {
type: jsPsychHtmlButtonResponse,
stimulus: '',
choices: [jsPsych.timelineVariable('picture_top_left'),
jsPsych.timelineVariable('picture_top_right'),
jsPsych.timelineVariable('picture_bottom_left'),
jsPsych.timelineVariable('picture_bottom_right')],
button_html:
['<button class="jspsych-btn" style = "position:absolute; left:80px; top: 50px">\
<img src="%choice%" style="width: 150px; height: 150px;"/></button>',
'<button class="jspsych-btn" style = "position:absolute; right:80px; top: 50px">\
<img src="%choice%" style="width: 150px; height: 150px;"/></button>',
'<button class="jspsych-btn" style = "position:absolute; left:80px; top: 380px">\
<img src="%choice%" style="width: 150px; height: 150px;"/></button>',
'<button class="jspsych-btn" style = "position:absolute; right:80px; top: 380px">\
<img src="%choice%" style="width: 150px; height: 150px;"/></button>'],
response_ends_trial: true,
...
}

Since our response options in this trial also represent our visual
stimuli, nothing is referenced in the stimulus parameter. The
array in the choices parameter contains references to four
different variables in the stimulus array, each pointing towards a
different image file. These references are used to generate four buttons
in the button_html parameter below, where the buttons’ size and
position is determined.
Since this is the critical trial for data collection, mouse-tracking,
additional variables and the unpacking function for the mouse-tracking
data are added. This is shown in the second part of the trial’s code
below.
var target_screen = {
...
extensions: [
{type: jsPsychExtensionMouseTracking,
params: {events: ['mousemove','mousedown']
}
}
],
data:{
component: 'experiment',
itemID:jsPsych.timelineVariable('itemID'),
condition: jsPsych.timelineVariable('condition'),
prompt: jsPsych.timelineVariable('prompt'),
prime: jsPsych.timelineVariable('prime'),
top_left:jsPsych.timelineVariable('top_left'),
top_right:jsPsych.timelineVariable('top_right'),
bottom_left:jsPsych.timelineVariable('bottom_left'),
bottom_right:jsPsych.timelineVariable('bottom_right'),
list: jsPsych.timelineVariable('list')
},
on_finish: function(data) {
processMouseTrackingData(data.mouse_tracking_data);
},
}
How to Modify
Suppose we wanted to investigate the following: Are phonological
competition effects in word recognition moderated by priming the
semantic category of the target word? In this experiment, participants
hear an auditory prompt naming the target image (‘click on the …’) while
looking at a screen with the target and three distractor images. At last
one of the distractors is a phonological competitor to the target image.
Target and competitor are however semantically unrelated (e.g. target =
‘plane’ and competitor = ‘plate’).
The masked prime word preceding the target screen is either semantically
related or unrelated to the target image (e.g. ‘cloud’ vs. ‘book’ in our
example). The critical question is whether the phonological competition
effect, which arguably manifests in a later response compared to the
absence of a competitor, is equally pronounced when the target is
semantically primed and when it isn’t.
Demonstrating this in code would require some space due to the rather
long stimulus objects of scenario 3, so here is an abreviated version:
1. Our stimulus array needs a variable pointing to the
auditory prompt files. We also add a condition variable for
later reference. Our four picture_path variables are still used
to display the four images, among which are the target and competitor.
The prime variable is used in the same way as before..
2. The original prompt trial now always
displays the same short message flanked by plus signs. This could for
example be ‘+++ get ready +++’. This is followed by the prime
trial, where the prime word is presented and also flanked by plus signs
(e.g. +++ cloud +++)
3. The target_screen trial is changed from an
html-button-response trial into an audio-button-response trial. This
allows us to keep our current button grid intact and to simply add our
new audio prompt variable in the trial’s stimulus parameter.
Pre- and Post-Experiment Elements
Listed below are elements which either precede or follow the main
experiment sequence. If they are to be part of an experiment session,
they need to be included in the global timeline
.
Instructions
The instruction element is a jsPsych trial specifically
designed to display instructional text over multiple pages. This is done
via the trial’s pages parameter, which takes an array as input
with each array position corresponding to a page.
By default, participants can navigate between instruction pages by using
the arrow keys. Additionally, you can render buttons for navigation, as
is done in the code below. Setting _show_clickable_nav to true
will generate the respective buttons, which can each be labeled via a
respective parameter (see below).
var instruction = {
type: jsPsychInstructions,
pages:[,,,],
show_clickable_nav:true,
button_label_previous: 'previous',
button_label_next: 'next',
};
There are two basic options for displaying instructional text which are
each explained below.
Display Text via Image Files
This may be helpful if an instruction page contains large amounts of
text. You can reference a pre-generated image file displaying your text
in a given array position in the pages parameter. This way, the
image will be displayed on the respective page. Additionally, you may
include the css_classes parameter to render the image over the
entire screen (otherwise it will be displayed within the display area,
which would defeat the purpose). An instruction page will then look like
below.
var instruction = {
type: jsPsychInstructions,
css_classes: ['fullscreen-div'],
pages:[
'<img src = "instructions/p1.jpg" style = "position:absolute; left: 10%;"></img>',
'<img src = "instructions/p2.jpg" style = "position:absolute; left: 10%;"></img>',
]

Rendering the image over the entire screen will prevent the rendering of
navigation buttons. Participants can still use the default navigation
via the arrow keys, but this information needs to be included in the
instruction text (see above).
The image option is currently the default in the template’s script. The
instructions folder contains a PowerPoint presentation with two
slides which can be used as templates to generate instruction pages.
Display Text Dircetly
You can also display your instruction text directly. This may be more
intuitive if you don’t have large amounts of instructional text. To do
this, enter your text in the respective array position in the
pages parameter, and the text will appear on the respective
page inside the display area. You can also include navigation buttons
with this method.
var instruction = {
type: jsPsychInstructions,
pages:[
'This is the first instruction page',
'This is the second instruction page',
],
show_clickable_nav:true,
button_label_previous: 'previous',
button_label_next: 'next',
};

Pre- and Post-Experiment Survey
Both the pre- and post-experiment survey trials are defined in the
General Components section of the script and are, except for
their respective item names, structurally identical. They are both
survey-html-form trials. This trial type allows us to define different
types of survey items in the same document. jsPsych offers various
survey plugins, but these are typically capable of only generating one
specific type of item in a respective trial, so using the
html-survey-form trial makes for less restrictive survey generation. The
drawback, however, is that each survey item needs to be defined from
scratch using html code, which can be rather time and space consuming
depending on the type of item you want to display.
Both survey forms contain dummies of four frequently used survey items
which you can copy-paste for as many times as you need items of the
respective type. Note, however, that each item needs a unique name in
order to be identified later. Below each item type included in the
survey templates is demonstrated.
Open Item
This item consists of a single input tag specifying text as appropriate
input, an item name, and the size of the input window. Above we add a
dummy text which can be used to specify the question directed at
participants.
'<p style = "text-align: left; font-size:16px;">1. This is an open item </p> \
<input type = "text" name = "pre_dummy_text" size = "40"/>'
Numeric
This is structurally similar to the previous item. In a single tag,
numbers are specified as appropriate input and the item gets a unique
name. We again add a dummy text above the item.
'<p style = "text-align: left; font-size:16px;">2.Indicate a number here </p> \
<input type = "number" name = "pre_dummy_num" />'
Multiple-Choice
This requires a bit more code: We want to offer three choices
represented by three labelled tick boxes ordered vertically. To do this,
we create three divs which each contain one input tag. By specifying
checkbox as input type, each tag will generate a tick box.
Next, each box gets a unique ID (in our case these are a, b and c) but,
crucially, each box gets the same name. This makes it
clear that the three boxes represent possible values of the same item.
Each box then gets a unique value. This is the value that will appear in
the results file if a given box is ticked. In our case, these values are
the dummies a, b and c.
Next to the tick box, we display the response
options the boxes represent. This label is enclosed in a separate label
bracket whose first tag references the ID of the respective tick box. We
again use the dummies a, b and c to overtly label our tick boxes. We
again display a dummy text above the item.
'<p style = "text-align: left; font-size:16px;">3. This is a multiple-choice item </p> \
\
<div style ="font-size:16px;"><input type="checkbox" id="a" name="pre_dummy_multi" value="a" />\
<label for="a">this is box a</label></div> \
\
<div style ="font-size:16px;"><input type="checkbox" id="b" name="pre_dummy_multi" value="b" />\
<label for="b">this is box b</label> </div> \
\
<div style ="font-size:16px;"><input type="checkbox" id="c" name="pre_dummy_multi" value="c" />\
<label for="b">this is box c</label> </div>'
Likert
This also requires some workaround: To display a five-point-likert
scale, we create an unordered list, and the elements inside this list
are input tags. Normally, the list elements would be ordered vertically.
To present them horizontally like in a likert scale, an element is added
in the added_style.css file which will display the list
elements horizontally. This element is referenced as the list’s id.
The first and last element of the list are the labels for the start and
end of the scale respectively (‘not at all’ and ‘very much’). Between
those, we add five elements containing input tags corresponding to the
values of our scale. By specifying radio as the input type in
each tag, we get a round element similar to a tick box, but only one of
these can be ticked at a time. Each element then gets the same
name, indicating that they represent different values of the
same item. Finally, each tag gets a value corresponding to a value on
the likert scale (1-5). We then add a dummy text above the item.
'<p style = "text-align:left; font-size:16px;">4. This is a likert-scaled item <\p> \
\
<ul id="likert"> \
<li style = "font-size:16px;"> not at all </li> \
\
<li><input type="radio" name="pre_dummy_likert" value="1" /></li> \
<li><input type="radio" name="pre_dummy_likert" value = "2" /></li> \
<li><input type="radio" name="pre_dummy_likert" value = "3" /></li> \
<li><input type="radio" name="pre_dummy_likert" value = "4" /></li> \
<li><input type="radio" name="pre_dummy_likert" value = "5" /></li> \
\
<li style = "font-size:16px;"> very much </li> \
</ul>\'
All of the elements displayed above make up the survey page, which will
look like on the image below.

Both survey trials will each generate a response variable. This variable
contains one object with answers for all items of the survey. The items
are referenced by the name they get in the respective input tag.
Task Start and Finish
Both of these elements are defined in the General Components
section of the script. They are simple html-button-response trials
forming a bracket around the experiment sequence.
The start_task trial will inform participants that by clicking
the button below, they will start the experiment. It also informs them
on how the cursor-orientation trial works.
var start_task = {
type: jsPsychHtmlButtonResponse,
stimulus: '<p>Click the button below to start the experiment.</p>\
<p> Before each trial, you will see a black circle. \
Move your cursor into the circle to initiate the next trial.</p>',
choices: ['ready'],
response_ends_trial: true,
};
The finish_task trial will follow the experiment sequence and
inform participant’s that they have completed the task. Clicking the
Continue button, the will proceed to either the post-experiment
survey (if included) or to the debrief screen.
var finish_task = {
type: jsPsychHtmlButtonResponse,
stimulus: 'You have completed the task. Click the button below to proceed.',
choices: ['Continue'],
response_ends_trial: true,
}
Debrief
The debrief element is defined in the General
Components section of the script. It is another simple
html-button-response trial instructing participants to end the
experiment session by clicking on the respective button. The debrief
message also references the participant’s subject ID, which is generated
earlier in the Global_Settings section.
After clicking on the End button, the results data will be
downloaded to your device as a .csv file and they will be displayed on
screen in .json format.
var debrief = {
type: jsPsychHtmlButtonResponse,
stimulus: function(){
return "<p>Thank you for your participation.</p>\
<p>Your participant code is displayed below.</p>"
+ subject_id +
"<p>Press the button to end the experiment.</p>"
},
choices: ['End'],
}
Other Elements and Functions
Initial Timeline Elements
The elements discussed in the following are functional rather than
content elements. They should be added in the
global timeline before any of the content elements discussed above.
This will ensure that the experiment session runs in the intended way.
Full Screen Mode
This trial is defined in the Genral Components section of the
script. It will send the browser into full screen mode when the trial’s
automatically generated button is pressed.
var fullscreen_mode = {
type: jsPsychFullscreen,
fullscreen_mode: true
};
Browser Check
This trial is defined in the Genral Components section of the
script. It checks whether the current size of the browser window
corresponds to the minimum width and height specified in the trial’s
parameters. In the current setting, the minimum values correspond to the
size of the display area . If the window size is
smaller than the specified minimum, a message will be displayed
instructing participants to enlarge the window.
var browser_check = {
type:jsPsychBrowserCheck,
feature: ["width","height"],
minimum_height: 600, //in pixels
minimum_width: 800,//in pixels
window_resize_message:
'<p>Your browser window is too small to complete this experiment. \
Please maximize the size of your browser window. \
If your browser window is already maximized, \
you will not be able to complete this experiment.</p> \
<p>The minimum window width is <span id="browser-check-min-width"></span> px.</p> \
<p>Your current window width is <span id="browser-check-actual-width"></span> px.</p>\
<p>The minimum window height is <span id="browser-check-min-height"></span> px.</p>\
<p>Your current window height is <span id="browser-check-actual-height"></span> px.</p>.'
};
Note that the browser_check trial will also record the width
and height of the screen on which the experiment is currently displayed.
This is an important reference for interpreting the cursor coordinates
recorded during the experiment.
Selecting Functions
There are two kinds of selecting functions
in the script, which are structurally very similar. These are:
- The function selecting a scenario timeline for the
main_sequence variable, and
- The function selecting a list-specific stimulus array for a
scenario’s timeline variable.
Both functions take a parameter from the Global Settings
section as input. These are the main_sequence_choice parameter
for the scenario-selecting function, and the list_choice
parameter for the list-selecting function. These inputs are then
processed by a series of if-else statements, which assign a particular
scenario or a particular list to a variable internal to the function
based on the value of the input-parameter, and the variable defined by
this process is then returned by the function.
The code for both functions is shown below.
function getMainSequence(main_sequence_choice) {
var main_sequence;
if (main_sequence_choice === 1) {
main_sequence = Scenario1();
} else if (main_sequence_choice === 2) {
main_sequence = Scenario2();
} else if (main_sequence_choice === 3) {
main_sequence = Scenario3();
} else {
console.error("Invalid main sequence choice");
return null;
}
return main_sequence;
}
function listAssign3 (list_choice) {
var list;
if (list_choice === 1) {
list = three_list_a;
} else if (list_choice === 2) {
list = three_list_b;
} else if (list_choice === 3) {
list = three_list_c;
}
return list
}
The list-selecting function above is the one from scenario 3, but
structurally identical functions exist for scenarios 1 and 2. If your
experiment includes more than three lists, the function above can simply
be expanded by as many conditional statements as necessary.
Interpreting the Response Variable
Button-response trials, such as those used in
scenarios 1 and 3, will automatically generate a response variable with
a number indicating which button was chosen. The number identifies a
button by its position in the trial’s choices array, so the
first button defined therein will be indicated by the number 0, the
second by the number 1 etc.
This number isn’t very informative if we can’t relate it to our
experimental variables. For example, in the critical trials of scenario
1, we want to know whether participants chose the label ‘cup’ or the
label ‘bowl’. We know that the first button in the trial’s
choices array is the left button, and the second one is the
right button, so the response variable can tell us which button was
chosen (0 = left, 1 = right), but the respective labels don’t always
appear on the same side. So we can’t infer the chosen label from this
number.
The following is one way to work around this problem as exemplified by
scenario 1: Suppose we wanted to end up with a dummy-coded results
variable telling us whether a participant chose the label ‘cup’ (= 1) or
not(= 0), which would mean that they chose the label ‘bowl’. Since we
know what button (left vs. right) gets which number in the response
variable (0 vs. 1), we can include a variable in our stimulus array
which tells us where the ‘cup’ label will be, and therefore, which
number the results variable should have if the label was chosen. This
could look like below.
var stimulus_set_scenario1 = [
...
{itemID:6, list:'c', condition: 'critical', picture:'critical_1.png',
picture_path: 'pictures/critical_1.png', left: 'cup', right: 'bowl', cup: 0},
{itemID:7, list:'a', condition: 'critical', picture:'critical_2.png',
picture_path: 'pictures/critical_2.png', left: 'bowl', right: 'cup', cup: 1},
{itemID:8, list:'b', condition: 'critical', picture:'critical_3.png',
picture_path: 'pictures/critical_3.png', left: 'cup', right: 'bowl', cup: 0},
{itemID:9, list:'c', condition: 'critical', picture:'critical_4.png',
picture_path: 'pictures/critical_4.png', left: 'bowl', right: 'cup', cup: 1},
{itemID:10, list:'a', condition: 'critical', picture:'critical_5.png',
picture_path: 'pictures/critical_5.png', left: 'cup', right: 'bowl', cup: 0},
...
]
The cup variable we have added above tells us which number in
the trial’s response variable should correspond to the choice
of the ‘cup’ label: If the label is displayed on the left button, this
number should be 0. When the label is displayed on the right button, it
should be 1.
If we add our new variable to the trial data
, we can use both our cup variable and the trial’s
response variable in our analysis to define the intended
variable telling us which label was chosen. For example, a line of R
code defining our variable would look like below. Our results data are
stored in an object named data in this example:
data$label_choice <- ifelse (data$cup == data$response, 1, 0)
The code above will generate a new variable called label_choice
in our data frame, which will assume the value 1 whenever the
cup and response variable have the same value,
i.e. when the ‘cup’ label was chosen, and will assume the value 0
otherwise, i.e. when the ‘bowl’ label was chosen.
Interpreting the Cursor Coordinates
The cursor coordinates recorded via the
mouse-tracking extension encode the cursor’s distance in pixels from the
top-left corner of the screen. You can relate this measure to the
cursor’s position within the display area with the following
information:
screen width: Recorded during the
browser_check trial and included in the results file.
display area width and height: Determined in the
global_settings section, currently 800px and 600px
respectively.
display area position: Determined in the .css file,
currently in the horizontal center and 100px below the top of the
screen.
Scaling the x-coordinate
To obtain the cursor position relative to the left margin of the display
area from a recorded coordinate \(x_i\), we can do the following:
- From the results produced by the browser_check trial, we
get the width of the screen, which we will call \(size\).
- \(\frac{size}{2}\) will give us the
horizontal \(center\) of the
screen.
- From the display_area_setting parameter in the
global_settings section, we get the \(width\) of the display area.
- \(center - \frac{width} {2}\) will
give us the \(margin_{left}\) of the
display area.
- \(x_i - margin_{left}\) will scale
the x-coordinate to the width of the display area. Any value which is
either negative or larger than the display area’s predefined width
(currently 800px) then corresponds to a position outside the display
area.
Scaling the y-coordinate
To obtain the cursor position relative to the bottom margin of the
display area from a recorded coordinate \(y_i\), we can do the following:
- From the display_area_setting parameter in the
global_settings section, we get the \(height\) of the display area.
- From the display area’s margin parameter in the .css file,
we get the \(margin_{top}\) of the
display area (currently 100px).
- \(height + margin_{top}\) will give
us the \(margin_{bottom}\) of the
display area.
- \(margin_{bottom} - y_i\) will
scale the y-coordinate to the height of the display area. Any value
which is either negative or larger than the display area’s predefined
height (currently 600px) then corresponds to a position outside the
display area.
Automatic Stimulus-Object Generation
Depending on the size of your experiment, it may be advantageous to
generate your stimulus object more or less automatically. You can do
this with the help of the R script generate_stimulus_objects.
In its current form, the script generates and exports as json files the
stimulus objects used in scenarios 1 and 2.
This option is especially useful in a scenario 2-type experiment, where
pretty much all of the writing of the stimulus object can be outsourced
to the script, as shown below.
library(jsonlite)
####retrieve file names from folders####
img_files <- list.files(path='pictures',full.names = TRUE, recursive = TRUE)
audio_files <- list.files(path='sounds',full.names = TRUE, recursive = TRUE)
#####Stimulus Object for Scenario 2#####
#get audio path from list of audio files
audio_path <- audio_files
#number of stimulus objects
n2 <- length(audio_path)
#get name of audio files without path
audio <- gsub("sounds/", '', audio_path)
#get unique id for each stimulus object
itemID <- c(1:n2)
#get list variable if required
list <- rep(c("a","b","c"), times = n2/3)
#create stimulus object as data frame
scenario2_df <- data.frame(itemID, list, audio, audio_path)
#convert data frame to json
stimulus_set_scenario2 <- toJSON(scenario2_df)
For scenario 1, a little more manual labor is required even with the
script since not all label options can be directly derived from the
available file names, but it may still save you some time.
For a scenario 3-type experiment, using a script may not be the
preferred option since most dependencies between variables can not be
easily derived from the available file names. For this reason, no code
block for generating stimulus_set_scenario3 is included in the
script. However, the script’s code may still be used to write at least
parts of the object.