Pushkin
  • Welcome!
  • Getting Started
    • Installing Pushkin and dependencies
      • macOS
      • Windows 10
        • Windows Subsystem for Linux
        • AWS EC2 Instance
      • Ubuntu Linux
    • Quickstart
      • Quickstart: Example Outputs
    • Deploying to AWS
      • Install required software.
      • Configure the AWS and ECS CLIs.
      • Register a domain.
      • Set up DockerHub.
      • Initialize AWS Deploy.
    • Tutorial: Simple Experiment
  • FAQ
    • FAQ
  • Advanced
    • Pushkin CLI
    • Using Experiment Templates
      • Lexical decision template
      • Grammaticality judgment template
      • Self-paced reading template
    • Experiment Component Structure
      • Experiment Config.yaml Files
      • Experiment Web Page Component
      • Worker Component, Migration, and Seed
    • Modifying Site Template
      • React Bootstrap
      • Header and Footer
      • Home Page
      • Findings Page
      • About Page
      • Feedback Page
    • Troubleshooting Pushkin
    • Pushkin Client
    • pushkin-api
      • API Controller Builder
      • Core API
    • Users & Authentication
    • Deployment
      • Deleting AWS
  • Developers
    • Developing with Pushkin
    • Getting Started on Development
    • Overview of Technologies
    • Testing Pushkin with Jest
    • Working with Templates
Powered by GitBook
On this page
  • Summary of tutorial content
  • Initial code
  • Move the timeline
  • Import plugins
  • Moving CSS styling

Was this helpful?

  1. Getting Started

Tutorial: Simple Experiment

PreviousInitialize AWS Deploy.NextFAQ

Last updated 1 year ago

Was this helpful?

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 . 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 ()

If you are not familiar with jsPsych, please consult the 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 and 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 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:

<!DOCTYPE html>
<html>
  <head>
    <title>My experiment</title>
    <script src="https://unpkg.com/jspsych@7.3.3"></script>
    <script src="https://unpkg.com/@jspsych/plugin-html-keyboard-response@1.1.2"></script>
    <link
      href="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;
      }
      .fixation p {
        width: 100%;
        position: absolute;
        margin: 0.25em;
      }
      .fixation p.top {
        top: 0px;
      }
      .fixation p.bottom {
        bottom: 0px;
      }
      .correct {
        border-color: green;
      }
      .incorrect {
        border-color: red;
      }
    </style>
  </head>
  <body></body>
  <script>
    const jsPsych = initJsPsych();

    const timeline = [];

    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 task
        let 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 debrief
        let 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

pushkin install experiment

You should now have a folder experiments/lex with the following content:

└── lex
    ├── api controllers
    ├── config.yaml
    ├── LICENSE
    ├── migrations
    ├── README.md
    ├── web page
    │    └── src
    │         ├── assets
    │         ├── experiment.js
    │         └── index.js
    └── worker

Open experiment.js. It should look like this:

import jsPsychHtmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response";

export function createTimeline(jsPsych) {
  const timeline = [];

  var hello_trial = {
    type: jsPsychHtmlKeyboardResponse,
    stimulus: "Hello world!",
  };

  timeline.push(hello_trial);

  return timeline;
}

Import plugins

Moving CSS styling

@import url("https://unpkg.com/jspsych@7.3.3/css/jspsych.css");

.fixation {
  border: 2px solid black;
  height: 100px;
  width: 200px;
  font-size: 24px;
  position: relative;
  margin: auto;
}
.fixation p {
  width: 100%;
  position: absolute;
  margin: 0.25em;
}
.fixation p.top {
  top: 0px;
}
.fixation p.bottom {
  bottom: 0px;
}

.correct {
  border-color: green;
}

.incorrect {
  border-color: red;
}

Follow the 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:

From the jsPsych code , 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.

In the jsPsych code , 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 ).

The experiment 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:

Quickstart
jsPsych
read more
documentation
here
moving the timeline
importing plugins
above
above
above
here