Dot Enumeration Task with jsPsych

This task was coded with jsPsych v7.2. The source code and materials are available in my GitHub

https://github.com/jianch/dotEnumerationTask

Here is the key javascript.

var jsPsych = initJsPsych({
  on_finish: function(){
    window.location.href = debrifurl},
});

/* url parameters*/
var id = jsPsych.data.getURLVariable("subjectid");
var debrifurl = "https://www.jianchen.info?subjectid=".concat(id)  // go to another task

 /* create timeline */
var timeline = []; 

/* preload images */
var preload = {
  type: jsPsychPreload,
  images: ['n1r1.png', 'n1r2.png', 'n1r3.png', 'n1r4.png','n1r5.png','n1r6.png', 'n1r7.png', 'n1r8.png',
           'n2r1.png', 'n2r2.png', 'n2r3.png', 'n2r4.png','n2r5.png','n2r6.png', 'n2r7.png', 'n2r8.png',
           'n3r1.png', 'n3r2.png', 'n3r3.png', 'n3r4.png','n3r5.png','n3r6.png', 'n3r7.png', 'n3r8.png',
           'n4r1.png', 'n4r2.png', 'n4r3.png', 'n4r4.png','n4r5.png','n4r6.png', 'n4r7.png', 'n4r8.png',
           'n5r1.png', 'n5r2.png', 'n5r3.png', 'n5r4.png','n5r5.png','n5r6.png', 'n5r7.png', 'n5r8.png',
           'n6r1.png', 'n6r2.png', 'n6r3.png', 'n6r4.png','n6r5.png','n6r6.png', 'n6r7.png', 'n6r8.png',
           'n7r1.png', 'n7r2.png', 'n7r3.png', 'n7r4.png','n7r5.png','n7r6.png', 'n7r7.png', 'n7r8.png',
           'n8r1.png', 'n8r2.png', 'n8r3.png', 'n8r4.png','n8r5.png','n8r6.png', 'n8r7.png', 'n8r8.png',
           'n9r1.png', 'n9r2.png', 'n9r3.png', 'n9r4.png','n9r5.png','n9r6.png', 'n9r7.png', 'n9r8.png',
           'n10r1.png', 'n10r2.png', 'n10r3.png', 'n10r4.png',
           ]};
timeline.push(preload);

// settings 
var pic_duration = 5000;
var fix_duration = [200,500,700,900,1000];
var pic_size = 400;


var FullScreenOn = {
    type: jsPsychFullscreen,
    message: "<p>The experiment will be in full screen mode once you click on the button.</p>",
    button_label: 'Full Screen Mode',
    fullscreen_mode: true
}
timeline.push(FullScreenOn)

/* instructions */
var welcome = {
  type: jsPsychHtmlKeyboardResponse,
  stimulus: '<p>Welcome to the Dot Enumeration Task.</p>' +
            '<p>In this task, we would like to know, as fast as you can and without making any mistakes, how many dots you see on the screen.</p>'+
            '<p>A cross will appear on the screen followed by a display of dots. </p>'+ 
            'Press the SPACE BAR as soon as you identify how many dots there are on the screen, and then select your answer immediately.<p>'+
            '<p><b>Please respond as accurately and quickly as possible.</b></p>'+
            'Press SPACEBAR to begin practice trials',
  choices: [' '],
};
timeline.push(welcome);


/* defining practice stimululi*/
var prac_stimuli = [
  {prac_stimulus: 'n1r1.png', correct_response:0},
  {prac_stimulus: 'n2r1.png', correct_response:1},
  {prac_stimulus: 'n3r1.png', correct_response:2},
  {prac_stimulus: 'n4r1.png', correct_response:3},
  {prac_stimulus: 'n5r1.png', correct_response:4},
  {prac_stimulus: 'n6r1.png', correct_response:5},
  {prac_stimulus: 'n7r1.png', correct_response:6},
  {prac_stimulus: 'n8r1.png', correct_response:7},
  {prac_stimulus: 'n9r1.png', correct_response:8},
  ];
  
  
var fixation = {
  type: jsPsychHtmlKeyboardResponse,
  stimulus: '<div style="font-size:48px;">+</div>',
  choices: "NO_KEYS",
  trial_duration: jsPsych.randomization.sampleWithReplacement(fix_duration, 1),
  data: {phase: 'fixation',},
};


var prac_stimulus = {
  type: jsPsychImageKeyboardResponse,
  stimulus: jsPsych.timelineVariable('prac_stimulus'),
  stimulus_height: pic_size,  
  maintain_aspect_ratio: true,
  choices: [' '],
  data: {
    phase: 'prac_stimulus',
    prac_stimli:jsPsych.timelineVariable('prac_stimulus'),
  },
};

// response and feedback
var msg;
var prac_response = {
  type: jsPsychHtmlButtonResponse,
  stimulus: '<p>How many dots were on the screen?</p>',
  choices: ['1','2','3','4','5','6','7','8','9','10'],
  prompt: "<p>Select a number</p>",
  data:{
    phase: 'practice_resp',
    correct_responses: jsPsych.timelineVariable('correct_response'),
  },
  on_finish: function(data){
    data.correct = data.response==jsPsych.timelineVariable('correct_response');
    if (data.correct){
      msg = "<p style='font-size:22px; color:green;'>Correct!</p>";
    } else {
      msg = "<p style='font-size:22px; color:red;'>Incorrect!</p>";
    }
  }
};

var practice_feedback = {
	type: jsPsychHtmlKeyboardResponse,
	trial_duration: 1000,
	choices: "NO_KEYS",
	stimulus: function(){return msg;},
};


var practice_procedure = {
  timeline: [fixation, prac_stimulus, prac_response, practice_feedback],
  timeline_variables: jsPsych.randomization.shuffleNoRepeats(prac_stimuli), // make sure that neighboring elements in the array are different.
  // randomize_order: true,
  repetitions: 1,
};	
timeline.push(practice_procedure);






// Formal Experiment 

var pre_test = {
  type: jsPsychHtmlKeyboardResponse,
  stimulus: '<p>This is the end of the practice trials. You will now begin the experiment trials.  </p> '+
            'Feedback will NOT be provided</p> ' + 
            'Press Spacebar to begin.</p>',
  choices: [' '],
}; 
timeline.push(pre_test);



var test_stimuli = [
  {stimulus: "n1r1.png",  correct_response: 0},
  { stimulus: "n1r2.png",  correct_response: 0},
  { stimulus: "n1r3.png",  correct_response: 0},
  { stimulus: "n1r4.png",  correct_response: 0},
  { stimulus: "n1r5.png",  correct_response: 0},
  { stimulus: "n1r6.png",  correct_response: 0},
  { stimulus: "n1r7.png",  correct_response: 0},
  { stimulus: "n1r8.png",  correct_response: 0},

  {stimulus: "n2r1.png",  correct_response: 1},
  { stimulus: "n2r2.png",  correct_response: 1},
  { stimulus: "n2r3.png",  correct_response: 1},
  { stimulus: "n2r4.png",  correct_response: 1},
  { stimulus: "n2r5.png",  correct_response: 1},
  { stimulus: "n2r6.png",  correct_response: 1},
  { stimulus: "n2r7.png",  correct_response: 1},
  { stimulus: "n2r8.png",  correct_response: 1},

  {stimulus: "n3r1.png",  correct_response: 2},
  { stimulus: "n3r2.png",  correct_response: 2},
  { stimulus: "n3r3.png",  correct_response: 2},
  { stimulus: "n3r4.png",  correct_response: 2},
  { stimulus: "n3r5.png",  correct_response: 2},
  { stimulus: "n3r6.png",  correct_response: 2},
  { stimulus: "n3r7.png",  correct_response: 2},
  { stimulus: "n3r8.png",  correct_response: 2},
  
  {stimulus: "n4r1.png",  correct_response: 3},
  { stimulus: "n4r2.png",  correct_response: 3},
  { stimulus: "n4r3.png",  correct_response: 3},
  { stimulus: "n4r4.png",  correct_response: 3},
  { stimulus: "n4r5.png",  correct_response: 3},
  { stimulus: "n4r6.png",  correct_response: 3},
  { stimulus: "n4r7.png",  correct_response: 3},
  { stimulus: "n4r8.png",  correct_response: 3},

  {stimulus: "n5r1.png",  correct_response: 4},
  { stimulus: "n5r2.png",  correct_response: 4},
  { stimulus: "n5r3.png",  correct_response: 4},
  { stimulus: "n5r4.png",  correct_response: 4},
  { stimulus: "n5r5.png",  correct_response: 4},
  { stimulus: "n5r6.png",  correct_response: 4},
  { stimulus: "n5r7.png",  correct_response: 4},
  { stimulus: "n5r8.png",  correct_response: 4},

  {stimulus: "n6r1.png",  correct_response: 5},
  { stimulus: "n6r2.png",  correct_response: 5},
  { stimulus: "n6r3.png",  correct_response: 5},
  { stimulus: "n6r4.png",  correct_response: 5},
  { stimulus: "n6r5.png",  correct_response: 5},
  { stimulus: "n6r6.png",  correct_response: 5},
  { stimulus: "n6r7.png",  correct_response: 5},
  { stimulus: "n6r8.png",  correct_response: 5},
  
  {stimulus: "n7r1.png",  correct_response: 6},
  { stimulus: "n7r2.png",  correct_response: 6},
  { stimulus: "n7r3.png",  correct_response: 6},
  { stimulus: "n7r4.png",  correct_response: 6},
  { stimulus: "n7r5.png",  correct_response: 6},
  { stimulus: "n7r6.png",  correct_response: 6},
  { stimulus: "n7r7.png",  correct_response: 6},
  { stimulus: "n7r8.png",  correct_response: 6},
  
  {stimulus: "n8r1.png",  correct_response: 7},
  { stimulus: "n8r2.png",  correct_response: 7},
  { stimulus: "n8r3.png",  correct_response: 7},
  { stimulus: "n8r4.png",  correct_response: 7},
  { stimulus: "n8r5.png",  correct_response: 7},
  { stimulus: "n8r6.png",  correct_response: 7},
  { stimulus: "n8r7.png",  correct_response: 7},
  { stimulus: "n8r8.png",  correct_response: 7},
  
  {stimulus: "n9r1.png",  correct_response: 8},
  { stimulus: "n9r2.png",  correct_response: 8},
  { stimulus: "n9r3.png",  correct_response: 8},
  { stimulus: "n9r4.png",  correct_response: 8},
  { stimulus: "n9r5.png",  correct_response: 8},
  { stimulus: "n9r6.png",  correct_response: 8},
  { stimulus: "n9r7.png",  correct_response: 8},
  { stimulus: "n9r8.png",  correct_response: 8},
  
  { stimulus: "n10r1.png",  correct_response: 9},
  { stimulus: "n10r2.png",  correct_response: 9},
  { stimulus: "n10r3.png",  correct_response: 9},
  { stimulus: "n10r4.png",  correct_response: 9},
];


/* define break trial */
var trial_count = 0;

var break_trial = {
  type: jsPsychHtmlKeyboardResponse,
  stimulus:  "<p style='font-size: 18px'>Please take a short break if needed.</p>" + 
          "<p style='font-size: 18px'>When you are ready, continue by pressing the SPACEBAR.</p>",
};


var break_conditional = {
  timeline: [break_trial],
  // block rest determination
  conditional_function: function() {
    // increment trial count - in first run through the timeline variables procedure, trial_count will be equal to 1
    trial_count++;
    if (trial_count % 41 == 0 && trial_count!=0) {
      // if the trial count is divisible by 40, then run the break trial
      return true;
    } else {
      // otherwise skip the break trial
      return false;
    }
  }
};




var test_stimulus = {
  type: jsPsychImageKeyboardResponse,
  stimulus: jsPsych.timelineVariable('stimulus'),
  stimulus_height: pic_size,  
  maintain_aspect_ratio: true,
  choices: [' '],
  data: {
    phase: 'test_stimulus',
    test_stimli:jsPsych.timelineVariable('stimulus'),
  },
};


var test_response = {
  type: jsPsychHtmlButtonResponse,
  stimulus: '<p>How many dots were on the screen?</p>',
  choices: ['1','2','3','4','5','6','7','8','9','10'],
  prompt: "<p>Select a number</p>",
  data:{
    phase: 'test_resp',
    correct_responses: jsPsych.timelineVariable('correct_response'),
  },
  on_finish: function(data){
    data.correct = data.response==jsPsych.timelineVariable('correct_response');},
};



var test_procedure = {
  timeline: [fixation, test_stimulus, test_response, break_conditional],
  timeline_variables: jsPsych.randomization.shuffleNoRepeats(test_stimuli),
  // randomize_order: true,
  repetitions: 2,
};	
timeline.push(test_procedure);




var post_test = {
  type: jsPsychHtmlKeyboardResponse,
  stimulus: '<p>You have finished the Dot Enumeration Task.</p> '+
            'Press Spacebar to start next task.</p>',
  choices: [' '],
}; 
timeline.push(post_test);





/* start the experiment */
jsPsych.run(timeline);