Pushkin
Search…
Tutorial: Simple Experiment

Summary of tutorial content

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 vanilla jsPsych. The tutorial below explains how to modify this code to run on Pushkin. This is a recommended tutorial for learning the ropes, but a more complete experiment template for lexical decisions 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.

Initial code

Below, we will adapt a simple lexical decision experiment. The original code can be found here. This repository consists of the base jsPsych installation and a single HTML file. We will be extracting the experiment code from the HTML file only:
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<script src="jspsych/jspsych.js"></script>
5
<script src="jspsych/plugins/jspsych-html-keyboard-response.js"></script>
6
<link rel="stylesheet" href="jspsych/css/jspsych.css">
7
<style>
8
.fixation { border: 2px solid black; height: 100px; width: 200px; font-size: 24px; position: relative; margin: auto; }
9
.fixation p { width: 100%; position: absolute; margin: 0.25em;}
10
.fixation p.top { top: 0px; }
11
.fixation p.bottom { bottom: 0px; }
12
13
.correct { border-color: green;}
14
.incorrect { border-color: red; }
15
</style>
16
</head>
17
<body></body>
18
<script>
19
var timeline = [];
20
21
var welcome = {
22
type: 'html-keyboard-response',
23
stimulus: '<p>Welcome to the experiment. Please press C to continue.</p>',
24
choices: ['c']
25
}
26
27
timeline.push(welcome);
28
29
var instructions = {
30
type: 'html-keyboard-response',
31
stimulus: '<p>You will see two sets of letters displayed in a box, like this:</p>'+
32
'<div class="fixation"><p class="top">HELLO</p><p class="bottom">WORLD</p></div>'+
33
'<p>Press Y if both sets are valid English words. Press N if one or both is not a word.</p>'+
34
'<p>Press Y to continue.</p>',
35
choices: ['y']
36
}
37
38
timeline.push(instructions);
39
40
var instructions_2 = {
41
type: 'html-keyboard-response',
42
stimulus: '<p>In this case you would press N</p>'+
43
'<div class="fixation"><p class="top">FOOB</p><p class="bottom">ARTIST</p></div>'+
44
'<p>Press N to continue to the start of the experiment.</p>',
45
choices: ['n']
46
}
47
48
timeline.push(instructions_2);
49
50
var trials = [
51
{word_1: 'SOCKS', word_2: 'SHOE', both_words: true, related: true},
52
{word_1: 'SLOW', word_2: 'FAST', both_words: true, related: true},
53
{word_1: 'QUEEN', word_2: 'KING', both_words: true, related: true},
54
{word_1: 'LEAF', word_2: 'TREE', both_words: true, related: true},
55
56
{word_1: 'SOCKS', word_2: 'TREE', both_words: true, related: false},
57
{word_1: 'SLOW', word_2: 'SHOE', both_words: true, related: false},
58
{word_1: 'QUEEN', word_2: 'FAST', both_words: true, related: false},
59
{word_1: 'LEAF', word_2: 'KING', both_words: true, related: false},
60
61
{word_1: 'AGAIN', word_2: 'PLAW', both_words: false, related: false},
62
{word_1: 'BOARD', word_2: 'TRUDE', both_words: false, related: false},
63
{word_1: 'LIBE', word_2: 'HAIR', both_words: false, related: false},
64
{word_1: 'MOCKET', word_2: 'MEET', both_words: false, related: false},
65
66
{word_1: 'FLAFF', word_2: 'PLAW', both_words: false, related: false},
67
{word_1: 'BALT', word_2: 'TRUDE', both_words: false, related: false},
68
{word_1: 'LIBE', word_2: 'NUNE', both_words: false, related: false},
69
{word_1: 'MOCKET', word_2: 'FULLOW', both_words: false, related: false}
70
]
71
72
var lexical_decision_procedure = {
73
timeline: [
74
{
75
type: 'html-keyboard-response',
76
stimulus: '<div class="fixation"></div>',
77
choices: jsPsych.NO_KEYS,
78
trial_duration: 1000
79
},
80
{
81
type: 'html-keyboard-response',
82
stimulus: function(){
83
return '<div class="fixation"><p class="top">'+jsPsych.timelineVariable('word_1', true)+'</p><p class="bottom">'+jsPsych.timelineVariable('word_2', true)+'</p></div>';
84
},
85
choices: ['y','n'],
86
data: {
87
both_words: jsPsych.timelineVariable('both_words'),
88
related: jsPsych.timelineVariable('related')
89
},
90
on_finish: function(data){
91
var char_resp = jsPsych.pluginAPI.convertKeyCodeToKeyCharacter(data.key_press);
92
if(data.both_words){
93
data.correct = char_resp == 'y';
94
} else {
95
data.correct = char_resp == 'n';
96
}
97
}
98
},
99
{
100
type: 'html-keyboard-response',
101
stimulus: function(){
102
var last_correct = jsPsych.data.get().last(1).values()[0].correct;
103
if(last_correct){
104
return '<div class="fixation correct"></div>';
105
} else {
106
return '<div class="fixation incorrect"></div>';
107
}
108
},
109
choices: jsPsych.NO_KEYS,
110
trial_duration: 2000
111
}
112
],
113
timeline_variables: trials,
114
randomize_order: true
115
}
116
117
timeline.push(lexical_decision_procedure);
118
119
var data_summary = {
120
type: 'html-keyboard-response',
121
stimulus: function(){
122
var mean_rt_related = jsPsych.data.get().filter({related:true, both_words:true, correct: true}).select('rt').mean();
123
var mean_rt_unrelated = jsPsych.data.get().filter({related:false, both_words:true, correct: true}).select('rt').mean();
124
return '<p>Average response time for related words: '+Math.round(mean_rt_related)+'ms</p>'+
125
'<p>Average response time for unrelated words: '+Math.round(mean_rt_unrelated)+'ms</p>'
126
},
127
choices: jsPsych.NO_KEYS
128
}
129
130
timeline.push(data_summary);
131
132
jsPsych.init({
133
timeline: timeline
134
})
135
</script>
136
</html>
Copied!

Move the timeline

Navigate to your pushkin project and create a new stub experiment, selecting "basic" for your template, selecting the latest release, and naming your experiment "lex":
1
pushkin install experiment
Copied!
You should now have a folder experiments/lex with the following content:
1
└── lex
2
├── api controllers
3
├── config.yaml
4
├── migrations
5
├── seeds
6
├── web page
7
│ ├── package-lock.json
8
│ ├── package.json
9
│ └── src
10
│ ├── assets
11
│ ├── experiment.js
12
│ └── index.js
13
└── worker
Copied!
Open experiment.js. It should look like this:
1
import jsPsych from 'pushkin-jspsych';
2
3
const timeline = []
4
5
var hello_trial = {
6
type: 'html-keyboard-response',
7
stimulus: 'Hello world!'
8
}
9
10
timeline.push(hello_trial);
11
12
export default timeline;
Copied!
From the jsPsych lexical experiment HTML file, copy everything between var timeline = [] and jsPsych.init({. Use this code to replace the code in /experiments/lex/web page/src/experiment.js that is between const timeline = [] and export default timeline. Note that the definition of the timeline and the exports still need to be in your file!

Import plugins

In the HTML file at the start of this tutorial, plugins are loaded as scripts inside javascript tags. To load plugins for use with Pushkin, use the loadScripts() method provided by pushkin-client. Open new/web page/src/index.js. Towards the middle of the document, you will see:
1
async startExperiment() {
2
this.setState({ experimentStarted: true });
3
4
jsPsych.data.addProperties({user_id: this.props.userID}); //See https://www.jspsych.org/core_library/jspsych-data/#jspsychdataaddproperties
5
await pushkin.connect('/api/pushkintemplate');
6
await pushkin.prepExperimentRun(this.props.userID);
7
await pushkin.loadScripts([
8
'https://cdn.jsdelivr.net/gh/jspsych/[email protected]/plugins/jspsych-html-keyboard-response.js',
9
]);
Copied!
This loads the jspsych-html-keyboard-response.js plugin provided with jsPsych v. 6.0.4. This is hosteed by jsdelivr, which for reasons of its own provides access to javascript files from github repositories. Any version of any official jsPsych plugin can be loaded this way. For more information, see the jsdelivr documentation.
Note: if you would like to include custom jsPsych plugins, read this page to learn more.

Static assets

The tutorial above does not require any images or videos. To use static assets, put them in the experiment assets folder (web page/src/assets). Pushkin prep will place them in an accessible public folder. This folder can be referred to using the environment variable process.env.PUBLIC_URL.
For example:
1
var test_stimuli = [
2
{ stimulus: process.env.PUBLIC_URL+"/blue.png"},
3
{ stimulus: process.env.PUBLIC_URL+"/orange.png"}
4
];
Copied!
No special imports are required.
Note that this works for local development. Depending on how you deploy to the web, this environment variable may not be available.
Last modified 1yr ago