Pushkin’s modularity means that, in principle, you could probably use any javascript-based experiment engine to write your experiments. However, we highly recommend using jsPsych. Pushkin has only been extensively tested with jsPsych, and all the documentation currently assumes you are using jsPsych.
The tutorial below starts with a simple lexical decision task written in plain jsPsych 7. The tutorial below explains how to modify this code to run in Pushkin. This is a recommended tutorial for learning the ropes, but a more complete experiment template for lexical decision is available to install through Pushkin (read more)
If you are not familiar with jsPsych, please consult the documentation first. We recommend you also walk through some of the tutorials.
Note: As of v3.6.0 of the Pushkin CLI, the procedures described here for moving the timeline and importing plugins can be automated if you choose to import a jsPsych experiment when you run pushkin install experiment and select the basic template (v5+). You can still do these manually if you choose. You may also need to do parts of these procedures in the course of modifying one of the other experiment templates.
Initial code
We will start with a simple lexical decision experiment. The code has been adapted from the experiment here in order to be compatible with jsPsych 7. You can save the code below as an .html file to run it as a standalone jsPsych experiment:
<!DOCTYPEhtml><html> <head> <title>My experiment</title> <scriptsrc="https://unpkg.com/jspsych@7.3.3"></script> <scriptsrc="https://unpkg.com/@jspsych/plugin-html-keyboard-response@1.1.2"></script> <linkhref="https://unpkg.com/jspsych@7.3.3/css/jspsych.css"rel="stylesheet"type="text/css" /> <style>.fixation {border:2px solid black;height:100px;width:200px;font-size:24px;position:relative;margin:auto; }.fixationp {width:100%;position:absolute;margin:0.25em; }.fixationp.top {top:0px; }.fixationp.bottom {bottom:0px; }.correct {border-color:green; }.incorrect {border-color:red; } </style> </head> <body></body> <script>constjsPsych=initJsPsych();consttimeline= [];var welcome = { type: jsPsychHtmlKeyboardResponse, stimulus: consent +"<p>Press spacebar to continue.</p>", choices: [" "], };timeline.push(welcome);var instructions_1 = { type: jsPsychHtmlKeyboardResponse, stimulus:` <p>You will see two sets of letters displayed in a box, like this:</p> <div class="fixation"><p class="top">HELLO</p><p class="bottom">WORLD</p></div> <p>Press Y if both sets are valid English words. Press N if one or both is not a word.</p> <p>Press Y to continue.</p> `, choices: ["y"], };timeline.push(instructions_1);var instructions_2 = { type: jsPsychHtmlKeyboardResponse, stimulus:` <p>In this case, you would press N.</p> <div class="fixation"><p class="top">FOOB</p><p class="bottom">ARTIST</p></div> <p>Press N to begin the experiment.</p> `, choices: ["n"], };timeline.push(instructions_2);var lexical_decision_procedure = { timeline: [ { type: jsPsychHtmlKeyboardResponse, stimulus:'<div class="fixation"></div>', choices:"NO_KEYS", trial_duration:1000, }, { type: jsPsychHtmlKeyboardResponse,stimulus:function () {let first_word =jsPsych.timelineVariable("word_1");let second_word =jsPsych.timelineVariable("word_2"); first_word ='<div class="fixation"><p class="top">'+ first_word +"</p>"; second_word ='<div class="fixation"><p class="bottom">'+ second_word +"</p>";return first_word + second_word; }, choices: ["y","n"], data: { both_words:jsPsych.timelineVariable("both_words"), related:jsPsych.timelineVariable("related"), },on_finish:function (data) {if (data.both_words) {data.correct =jsPsych.pluginAPI.compareKeys(data.response,"y"); } else {data.correct =jsPsych.pluginAPI.compareKeys(data.response,"n"); } }, }, { type: jsPsychHtmlKeyboardResponse,stimulus:function () {let last_correct =jsPsych.data.getLastTrialData().values()[0].correct;if (last_correct) {return'<div class="fixation correct"></div>'; } else {return'<div class="fixation incorrect"></div>'; } }, choices:"NO_KEYS", trial_duration:2000, }, ], timeline_variables: stimArray, randomize_order:true, };timeline.push(lexical_decision_procedure);var data_summary = { type: jsPsychHtmlKeyboardResponse,stimulus:function () {// Calculate performance on tasklet correct_related =jsPsych.data.get().filter({ related:true, correct:true }).count();let total_related =jsPsych.data.get().filter({ related:true }).count();let mean_rt_related =jsPsych.data.get().filter({ related:true, correct:true }).select("rt").mean();let correct_unrelated =jsPsych.data.get().filter({ related:false, both_words:true, correct:true }).count();let total_unrelated =jsPsych.data.get().filter({ related:false, both_words:true }).count();let mean_rt_unrelated =jsPsych.data.get().filter({ related:false, both_words:true, correct:true }).select("rt").mean();// Show results and debrieflet results =`<p>You were correct on ${correct_related} of ${total_related} related word pairings! Your average correct response time for these was ${Math.round( mean_rt_related )} milliseconds.</p> <p>For unrelated word pairings, you were correct on ${correct_unrelated} of ${total_unrelated}! Your average correct response time for these was ${Math.round( mean_rt_unrelated )} milliseconds.</p>`;return results + debrief; }, choices:"NO_KEYS", };timeline.push(data_summary);jsPsych.run(timeline); </script></html>
Move the timeline
Follow the Quickstart through pushkin install site or navigate to the root directory of an existing site. Create a new experiment named "lex" and select the latest version of the basic template:
pushkininstallexperiment
You should now have a folder experiments/lex with the following content:
From the jsPsych code above, copy everything between const timeline = [] and jsPsych.run(timeline); (excluding those lines). Paste those lines into /experiments/lex/web page/src/experiment.js (replacing the existing content) between const timeline = [] and return timeline. Thus you should now have a function createTimeline() within which you build up and finally return the timeline for the experiment.
Import plugins
In the jsPsych code above, plugins are loaded with <script> tags. In a Pushkin experiment, plugins are loaded with import statements. The basic template already includes the html-keyboard-response plugin as a dependency, so no additional modifications are needed. If you wanted to add additional jsPsych plugins to this experiment, you would simply use additional import statements in the same format (see examples here).
Moving CSS styling
The experiment above relies on CSS styling described in a <style> tag to display the experiment correctly. This styling needs be moved to /experiments/lex/web page/src/assets/experiment.css in order to apply your Pushkin experiment. The new CSS file will look like: