import { initJsPsych } from 'jspsych'; import 'jspsych/css/jspsych.css'; import jsPsychHtmlKeyboardResponse from '@jspsych/plugin-html-keyboard-response'; import jsPsychFullscreen from '@jspsych/plugin-fullscreen'; import jsPsychHtmlButtonResponse from '@jspsych/plugin-html-button-response'; import jsPsychSurvey from '@jspsych/plugin-survey'; import '@jspsych/plugin-survey/css/survey.css'; import './styles.css'; import { getStimulusMap } from './scripts/text-stimuli.js'; import { textStimuli } from './scripts/text-stimuli.js'; import JsPsychDieRoll from './plugins/jspsych-die-roll.js'; import JsPsychCaptcha from './plugins/jspsych-captcha.js'; import html from './utils/html.js'; const experiment_name = import.meta.env.VITE_EXPERIMENT_NAME; let prolific_id; let probe_condition; // will be set to ai or human based on the condition. let debug; let probe_order; // will be set to ai_first or human_first based on the condition const CAPTCHA_TRIAL_COUNT = debug ? 2 : 12; // set to 10 for main experiment function delayed_redirect(url) { setTimeout(() => { window.location = url; }, 5000); } const jsPsych = initJsPsych({ on_finish: function() { jsPsych.getDisplayElement().innerHTML = textStimuli.complete; }, on_close: function() { delayed_redirect(import.meta.env.VITE_CLOSED_URL); }, on_data_update: function() { if (debug) { console.log(jsPsych.data.get().json()); } }, show_progress_bar: true, }); debug = jsPsych.data.getURLVariable('debug') === 'true' || import.meta.env.VITE_DEBUG === 'true'; prolific_id = jsPsych.data.getURLVariable('PROLIFIC_PID'); const COND = Number(jsPsych.data.getURLVariable('C')); const probe_closing_text = `

On the next page, you will be asked about your suspicions and thoughts about this aspect of the study.

Press SPACE to continue

`; const probe_text_die = `

In this study, the die roll to determine captcha difficulty was rigged: the number you rolled was predetermined.

Therefore, the difficulty of the captcha task was also predetermined.

` + probe_closing_text; const probe_text_difficulty = `In this study, the die roll to determine captcha difficulty was indeed random.

However, the difficulty of the captcha task was pre-determined. It was unrelated to the die roll.

` + probe_closing_text; const probe_text_baseline = probe_closing_text const die_result = Math.random() < 0.5 ? 3 : 4; switch (COND) { case 0: probe_condition = 'die'; probe_order = 'die_first'; break; case 1: probe_condition = 'die'; probe_order = 'die_first'; break; case 2: probe_condition = 'difficulty'; probe_order = 'die_first'; break; case 3: probe_condition = 'difficulty'; probe_order = 'die_first'; break; case 4: probe_condition = 'die'; probe_order = 'difficulty_first'; break; case 5: probe_condition = 'die'; probe_order = 'difficulty_first'; break; case 6: probe_condition = 'difficulty'; probe_order = 'difficulty_first'; break; case 7: probe_condition = 'difficulty'; probe_order = 'difficulty_first'; break; case 8: probe_condition = 'baseline'; probe_order = 'die_first'; break; case 9: probe_condition = 'baseline'; probe_order = 'die_first'; break; case 10: probe_condition = 'baseline'; probe_order = 'difficulty_first'; break; case 11: probe_condition = 'baseline'; probe_order = 'difficulty_first'; break; } const stimulusMap = getStimulusMap(); const props = { condition: probe_condition, prolific_id: prolific_id, experiment_name: experiment_name, probe_order: probe_order, cond: COND, }; if (debug) { console.log(props); } jsPsych.data.addProperties(props); const timeline = []; const pre_consent_info = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('pre_consent_info'), }; const enter_fullscreen = { type: jsPsychFullscreen, fullscreen_mode: true, }; const consent_form = { type: jsPsychHtmlButtonResponse, stimulus: stimulusMap.get('consent'), choices: ['Exit', 'Continue'], on_finish: function(data) { if (data.response === 0) { jsPsych.abortExperiment(stimulusMap.get('no_consent')); } }, }; const instructions_1 = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('instructions_1'), }; const instructions_2 = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('instructions_2'), }; const instructions_3 = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('instructions_3'), }; const debrief = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('debrief'), }; const pre_survey_info = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('pre_survey_info'), }; const die_roll_practice_trial = { type: JsPsychDieRoll, prompt: html`

Before the real die roll, you can practice here.

Click the die once to start it rolling, then click it again to stop.

`, practice_trial: true, practice_roll_limit: 3, roll_duration: 2200, result_template: 'Practice roll {{roll_number}}/{{roll_limit}}: You rolled a {{value}}.', }; const die_roll_trial = { type: JsPsychDieRoll, prompt: html`

Click the die once to start it rolling, then click it again to stop.

`, rigged_value: die_result, roll_duration: 2200, result_template: `You rolled a {{value}} (moderate difficulty). Click 'continue' to proceed.`, }; const create_captcha_trial = trial_index => { return { type: JsPsychCaptcha, prompt: '

Enter the characters you see into the textbox below.

', difficulty: die_result, button_label: 'Continue', error_text: '', allow_refresh: false, require_correct: false, data: { trial_id: 'captcha_entry', captcha_index: trial_index + 1, captcha_total: CAPTCHA_TRIAL_COUNT, }, }; }; const pre_die_roll_info = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: `

Practice complete. Now you will roll a die to determine the difficulty of the captcha task.

Press SPACE to continue

`, }; const captcha_trials = Array.from({ length: CAPTCHA_TRIAL_COUNT }, (_, index) => create_captcha_trial(index) ); const die_probe_row = { text: 'I suspected that the die roll was not random, or the number I received was pre-determined.', value: 'SuspicionDie', }; const difficulty_probe_row = { text: 'I suspected that, contrary to what I was told, the captcha task difficulty was not determined by the die roll.', value: 'SuspicionDifficulty', }; const survey_function = survey => { survey.onAfterRenderPage.add(function(sender, options) { console.log('Survey page rendered:', sender.currentPage); if (survey.activePage.name === 'page2') { const nextButton = document.querySelector('#sv-nav-next > div > input'); if (nextButton) { let seconds = 20; const originalText = nextButton.value.replace(/\s*\(\d+\)$/, '') || 'Continue'; nextButton.disabled = true; nextButton.value = `${originalText} (${seconds})`; const interval = setInterval(() => { seconds--; nextButton.value = `${originalText} (${seconds})`; if (seconds <= 0) { clearInterval(interval); nextButton.disabled = false; nextButton.value = originalText; } }, 1000); } } }); }; const survey_1 = { type: jsPsychSurvey, survey_function: survey_function, survey_json: { showQuestionNumbers: false, completeText: 'Continue', pageNextText: 'Continue', pagePrevText: 'Previous', showPrevButton: false, pages: [ { name: 'page1', elements: [ { type: 'matrix', name: 'Please answer the following questions about your experience in the captcha task.', alternateRows: true, isAllRowRequired: debug ? false : true, rowOrder: 'random', rows: [ { text: `I felt lucky during the die roll.`, value: 'Luck', }, { text: `I felt unlucky during the die roll.`, value: 'Bad_luck', }, ], columns: [ { value: 5, text: 'Strongly agree', }, { value: 4, text: 'Agree', }, { value: 3, text: 'Neutral', }, { value: 2, text: 'Disagree', }, { value: 1, text: 'Strongly disagree', }, ], }, ], }, { name: 'page2', elements: [ { type: 'matrix', name: 'Please answer the following questions about your experience in the captcha task.', alternateRows: true, isAllRowRequired: debug ? false : true, rowOrder: 'random', rows: [ { text: `I found the captcha task difficult.`, value: 'Difficulty', }, { text: `I think I solved all the captchas correctly.`, value: 'Accuracy', }, { text: `I think I solved captchas faster than most other participants would have.`, value: 'Relative_performance', }, { text: `I think I solved captchas slower than most other participants would have.`, value: 'Relative_performance_slow', }, ], columns: [ { value: 5, text: 'Strongly agree', }, { value: 4, text: 'Agree', }, { value: 3, text: 'Neutral', }, { value: 2, text: 'Disagree', }, { value: 1, text: 'Strongly disagree', }, ], }, ], }, ], }, }; const pre_manip_info = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: function () { switch (probe_condition) { case 'die': return probe_text_die; case 'difficulty': return probe_text_difficulty; case 'baseline': return probe_text_baseline; default: return 'ERROR: probe condition not recognized'; } }, }; const survey_2 = { type: jsPsychSurvey, survey_function: survey_function, survey_json: { showQuestionNumbers: false, completeText: 'Done!', pageNextText: 'Continue', pagePrevText: 'Previous', showPrevButton: false, pages: [ { name: 'page1', elements: [ { type: 'matrix', name: "Please indicate your agreement with the following statements.", alternateRows: true, isAllRowRequired: debug ? false : true, rowOrder: 'random', rows: [ probe_order === 'die_first' ? die_probe_row : difficulty_probe_row, { text: `There's no question here. Select 'Disagree' to show that you're paying attention.`, value: 'AttentionCheck', }, probe_order === 'die_first' ? difficulty_probe_row : die_probe_row, ], columns: [ { value: 5, text: 'Strongly agree', }, { value: 4, text: 'Agree', }, { value: 3, text: 'Neutral', }, { value: 2, text: 'Disagree', }, { value: 1, text: 'Strongly disagree', }, ], }, ], }, { name: 'page2', elements: [ { type: 'comment', title: `Please write a sentence or two on what you thought the study was about.`, isRequired: debug == true ? false : true, }, { type: 'comment', title: ` Indicate any other thoughts or suspicions you had about the study. \n`, isRequired: debug == true ? false : true, } ], }, { name: 'page3', elements: [ { type: 'radiogroup', title: 'Please indicate your gender', choices: ['Male', 'Female', 'Other'], isRequired: debug ? false : true, colCount: 0, name: 'gender', }, { type: 'radiogroup', title: 'Please indicate your handedness', choices: ['Right', 'Left', 'Ambidextrous/Other'], isRequired: debug ? false : true, colCount: 0, name: 'handedness', }, { type: 'text', title: 'How old are you?', name: 'age', isRequired: debug ? false : false, inputType: 'number', min: 18, max: 100, defaultValue: 18, }, ], }, ], }, }; const main_experiment_timeline = [ instructions_1, instructions_2, die_roll_practice_trial, pre_die_roll_info, die_roll_trial, instructions_3, ...captcha_trials, pre_survey_info, survey_1, pre_manip_info, survey_2, debrief, ]; if (debug) { timeline.push(die_roll_trial); timeline.push(...main_experiment_timeline); } if (!debug) { timeline.push(pre_consent_info); timeline.push(enter_fullscreen); timeline.push(consent_form); timeline.push(...main_experiment_timeline); } jsPsych.run(timeline);