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:


  1. The backslashes only enable line breaks in the code, they do not produce line breaks in the output text.


  1. 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.


Preload Media

This trial is defined in the General Components section of the script. It will load media files prior to their presentation in the experiment sequence. This ensures that the timing intended for the stimulus presentation in a trial is not disrupted by additional loading time. The trial will stop if one or more files can’t be loaded, in which case it will display an error message.


var preload_media = {
        type:jsPsychPreload,
        //auto_preload:true,
        trials: main_sequence,
        continue_after_error: false,
        error_message: 'the experiment failed to load',
        show_detailed_errors:true,
    }


There are two basic options for preloading: When auto_preload is set to true, all media files the script can access will be loaded. Alternatively, you can use the trials parameter to only load the referenced media files from specific trials. In the current settings, the main_sequence variable is used as input for the trials parameter. This way, only the media referenced in the selected experiment scenario will be loaded.


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:


  1. The function selecting a scenario timeline for the main_sequence variable, and

  1. 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:


  1. From the results produced by the browser_check trial, we get the width of the screen, which we will call \(size\).


  1. \(\frac{size}{2}\) will give us the horizontal \(center\) of the screen.


  1. From the display_area_setting parameter in the global_settings section, we get the \(width\) of the display area.


  1. \(center - \frac{width} {2}\) will give us the \(margin_{left}\) of the display area.


  1. \(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:


  1. From the display_area_setting parameter in the global_settings section, we get the \(height\) of the display area.


  1. From the display area’s margin parameter in the .css file, we get the \(margin_{top}\) of the display area (currently 100px).


  1. \(height + margin_{top}\) will give us the \(margin_{bottom}\) of the display area.


  1. \(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.