Connecting jsPsych Experiment to Pavlovia

jsPsych version (e.g. 7.3.1):
Hello all,

Long-time viewer, first-time poster! I am having a rather maddening issue that I can’t seem to figure out, I have tried working from the demos, following the demo guide, but I cant seem to get this working appropriately. I have the experiment fully working online, however, when I try to add in the pavlovia initialization variable to the timeline, it simply produces a blank screen that will not advance to the experiment. This experiment uses a jsPsych plugin called Audio_Tokens that is not a base plugin for jsPsych, but it runs fine online. Really just trying to get it to connect to pavlovia so the data is saved. I am hoping this has something to do with the way the plugins are called in at the beginning, or something of that sort, but I have tried changing them programmatically to no avail. Any advice would be greatly appreciated.

In the version currently in the repository I have removed the pavlovia_init and pavlovia_finish variables from the timeline, so you can see how it runs without connecting. The experiment code is below and the link to the repository is here: GitLab Repository

<!DOCTYPE html>
<html>
    <head>
        <title>SocialCateg_FreeClass</title>
        <script src="https://unpkg.com/jspsych@7.0.0"></script>
        <script src="audio_tokens-main_labeller/js/jspsych-audio-tokens-v7.js"></script>
        <script src="jspsych/dist/plugin-survey-text.js"></script>
        <script src="audio_tokens-main_labeller/js/audio-tokens.js"></script>
        <script src="https://d3js.org/d3.v4.min.js"></script>
        <script src="jatos.js"></script>
        <script src="https://unpkg.com/@jspsych/plugin-instructions@1.1.4"></script>
        <script type="text/javascript" src="lib/vendors/jquery-2.2.0.min.js"></script>
	    <script type="text/javascript" src="lib/jspsych-pavlovia-2020.2.js"></script>
        <link href="https://unpkg.com/jspsych@7.0.0/css/jspsych.css" rel="stylesheet" type="text/css"/>
    </head>
    <body>
    </body>
    <script>
        // Arrays with stimulus file paths
        var practice_stim = [
            'audio_stim/Practice/cven_17_17551_84473_512103.wav',
            'audio_stim/Practice/cven_10_19680_84473_665433.wav',
            'audio_stim/Practice/cven_09_26764_84473_17637624.wav',
            'audio_stim/Practice/cven_08_19497_84473_17246733.wav',
            'audio_stim/Practice/cven_07_27838_84473_566483.wav',
            'audio_stim/Practice/cven_06_31405_84473_97708.wav',
            'audio_stim/Practice/cven_05_14026_84473_17255724.wav',
            'audio_stim/Practice/cven_03_26059_84473_17388318.wav',
            'audio_stim/Practice/cven_00_02286_84473_617520.wav'
        ]

        var FC_stimuli = [
        'audio_stim/Trials/PRG-S-CF-004_HINT_38.wav',
        'audio_stim/Trials/PRG-S-CF-007_HINT_38.wav',
        'audio_stim/Trials/PRG-S-CF-009_HINT_38.wav',
        'audio_stim/Trials/PRG-S-CF-011_HINT_38.wav',
        'audio_stim/Trials/PRG-S-CM-001_HINT_38.wav',
        'audio_stim/Trials/PRG-S-CM-003_HINT_38.wav',
        'audio_stim/Trials/PRG-S-CM-005_HINT_38.wav',
        'audio_stim/Trials/PRG-S-CM-008_HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-002_HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-003 HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-004 HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-007 HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-015 HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-017_HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-019 HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-023_HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-025 HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-026 HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-028_HINT_38.wav',
        'audio_stim/Trials/PRG-S-T-030_HINT_38.wav'
        ]

        function shuffle(array) {
            let currentIndex = FC_stimuli.length,  randomIndex;
            // While there remain elements to shuffle.
            while (currentIndex != 0) {
                // Pick a remaining element.
                randomIndex = Math.floor(Math.random() * currentIndex);
                currentIndex--;
                // And swap it with the current element.
                [array[currentIndex], array[randomIndex]] = [
                array[randomIndex], array[currentIndex]];
            }
            }
        shuffle(FC_stimuli);
		
        /* init connection with pavlovia.org */
		var pavlovia_init = {
			type: "pavlovia",
			command: "init"
		};


        var demog_trial = {
            type: jsPsychSurveyText,
            questions: [
                {prompt: 'Please enter subject ID (ex. "SC_001").', name: 'id', required: true}, 
                {prompt: 'Please enter subject gender (M/F/N).', name: 'gender', required: true},
                {prompt: 'Please enter subject age.', name: 'age', required: true}
            ],
            data: {task_part: 'demog_question'}
        }
        // var PracTrial_Inst = {
        //     type: jsPsychInstructions,
        //     pages: [
        //     'Welcome to the experiment. On the following screen you will see a number of colored dots around a large circle. </p> Each dot is a different talker. You are being asked to make groups talkers however you would like to by dragging the colored dots onto the circle. Click next to begin.'
        //     ],
        //     show_clickable_nav: true
        // }
        
        // var FC_practice_trial = {
        //     type: jsPsychAudioTokens,
        //     ratingtype: 'cluster',
        //     stimuli: practice_stim,
        //     force_listen: false,
        //     loop: false,
        // }

        var FreeTrial_Inst = {
            type: jsPsychInstructions,
            pages: [
            'On the following screen you will see a number of colored dots around a large circle. </p> Each dot is a different talker. </p> Please make groups talkers however you would like to by dragging the colored dots inside the circle.</p> To help you group talkers, you will see lines appear when you drag one talker close to another. </p> Click next to continue and then click start to begin.'
            ],
            show_clickable_nav: true
        }

        var FC_free_trial = {
            type: jsPsychAudioTokens,
            ratingtype: 'cluster',
            stimuli: FC_stimuli,
            force_listen: false,
            loop: true,
            preload_audio: false,
            user_labels: "How would you label the clusters you've made?\n(Add one label per line)"
        }
        
        var GenderTrial_Inst = {
            type: jsPsychInstructions,
            pages: [
            'For the following trial, please groups talkers based on their gender by dragging the colored dots onto the circle. Click next to begin.'
            ],
            show_clickable_nav: true
        }
        
        var FC_prompted_trial = {
            type: jsPsychAudioTokens,
            ratingtype: 'cluster',
            stimuli: FC_stimuli,
            force_listen: false,
            loop: true,
            preload_audio: false,
            user_labels: "How would you label the clusters you've made?\n(Add one label per line)"
        }

		var pavlovia_finish = {
			type: "pavlovia",
			command: "finish",
			participantId: "JSPSYCH-DEMO"
		};

        // Add all trials to a timeline array
        var timeline = [
            demog_trial,
            FreeTrial_Inst,
            FC_free_trial,
            GenderTrial_Inst,
            FC_prompted_trial
            
        ]

        
        var jsPsych = initJsPsych({
            show_progress_bar: true,
            on_finish: function(){
                jsPsych.data.displayData();
                // get the ID that was entered from the jsPsych data
                var id = jsPsych.data.get().filter({task_part: 'demog_question'}).values()[0].response.id;
                var gender = jsPsych.data.get().filter({task_part: 'demog_question'}).values()[0].response.gender;
                var age = jsPsych.data.get().filter({task_part: 'demog_question'}).values()[0].response.age;
                // add this ID to the data for all trials
                jsPsych.data.addProperties({ID: id});
                jsPsych.data.addProperties({Gender: gender});
                jsPsych.data.addProperties({Age: age});
                // combine the subject ID with the file extension (and any other text) to dynamically create the file name
                var file_name = id + '_' + gender + '_' + age + '_data.csv';
                // save the data with this file name
                jsPsych.data.get().localSave('csv',file_name);
                jatos.endStudy(jsPsych.data.get().json());
            }
        });
        jsPsych.run(timeline);
    </script>
</html>
1 Like

The version of jsPsych Pavlovia uses is 7.1.2. Right now you’re pulling jsPsych from outside pavlovia with version 7.0.0. It’s possible that the Pavlovia interface functions require jsPsych 7.1.2 specifically, but I’m not sure. You could try pulling your jspsych version from pavlovia directly by replacing the unpkg references with these and see if it works better, assuming it doesn’t break anything else:

<script type="text/javascript" src="lib/vendors/jspsych-7.1.2/jspsych.js"></script>
<link rel="stylesheet" type="text/css" href="lib/vendors/jspsych-7.3.4/css/jspsych.css"/>

See also Pavlovia

1 Like

Unfortunately, the tutorial website is out of date. Using jsPsych 7.1.2 from the tutorial can't be loaded