import { initJsPsych } from 'jspsych'; import 'jspsych/css/jspsych.css'; import jsPsychHtmlKeyboardResponse from '@jspsych/plugin-html-keyboard-response'; import generateUniqueUsernames from './scripts/name-gen.js'; import jsPsychFullscreen from '@jspsych/plugin-fullscreen'; import jsPsychHtmlButtonResponse from '@jspsych/plugin-html-button-response'; import jsPsychLobby from './scripts/plugin-lobby.js'; import jsPsychSurvey from '@jspsych/plugin-survey'; import '@jspsych/plugin-survey/css/survey.css'; import './styles.css'; import { getStimulusMap } from './scripts/text-stimuli.js'; import jsPsychObjectMoving from './scripts/plugin-object-moving.js'; import { textStimuli } from './scripts/text-stimuli.js'; const total_participants = import.meta.env.VITE_TOTAL_PARTICIPANTS || 2; const uniqueUsernames = generateUniqueUsernames(total_participants); 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 = false; let probe_order; // will be set to ai_first or human_first based on the condition const short_version = true; // just using the short version of the task 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()); } }, }); debug = jsPsych.data.getURLVariable('debug') === 'true'; prolific_id = jsPsych.data.getURLVariable('PROLIFIC_PID'); const COND = Number(jsPsych.data.getURLVariable('C')); const probe_preamble = 'In this experiment, we told you that you were playing a game with a partner. However, due to the difficulty of implementing multi-participant online studies, your partner was actually '; const probe_closing_text = 'We would like to know what you thought about your partner. Please share your thoughts by indicating your agreement with the following statements.'; const probe_text_ai = probe_preamble + 'an AI agent trained to behave like a human participant. ' + probe_closing_text; const probe_text_human = probe_preamble + 'an experimenter pretending to be a participant. ' + probe_closing_text; let together_colour; let probe_text; switch (COND) { case 0: probe_condition = 'ai'; together_colour = 'blue'; probe_order = 'ai_first'; break; case 1: probe_condition = 'ai'; together_colour = 'red'; probe_order = 'ai_first'; break; case 2: probe_condition = 'human'; together_colour = 'blue'; probe_order = 'ai_first'; break; case 3: probe_condition = 'human'; together_colour = 'red'; probe_order = 'ai_first'; break; case 4: probe_condition = 'ai'; together_colour = 'blue'; probe_order = 'human_first'; break; case 5: probe_condition = 'ai'; together_colour = 'red'; probe_order = 'human_first'; break; case 6: probe_condition = 'human'; together_colour = 'blue'; probe_order = 'human_first'; break; case 7: probe_condition = 'human'; together_colour = 'red'; probe_order = 'human_first'; break; } const stimulusMap = getStimulusMap(together_colour); const props = { condition: probe_condition, together_colour: together_colour, prolific_id: prolific_id, experiment_name: experiment_name, probe_text: 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 initial_lobby = { type: jsPsychLobby, user_names: uniqueUsernames, end_number: total_participants, start_text: 'Searching for a partner', end_text: 'Partner found, the experiment will begin shortly.', join_interval: 5000, show_avatars: false, }; const lobby_slow = { type: jsPsychLobby, user_names: uniqueUsernames, end_number: total_participants, start_text: 'Waiting for your partner', end_text: 'Your partner is ready, the experiment will continue shortly.', show_avatars: false, join_interval: 7000, }; const lobby_fast = { type: jsPsychLobby, user_names: uniqueUsernames, end_number: total_participants, start_text: 'Waiting for your partner', end_text: 'Your partner is ready, the experiment will continue shortly.', show_avatars: false, join_interval: 500, }; const multi_user_instructions = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('multi_user_instructions'), }; 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 instructions_4 = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('instructions_4'), }; const pre_practice_instructions = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('pre_practice_instructions'), }; const pre_task_instructions = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('pre_task_instructions'), }; const debrief = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('debrief'), }; const pre_survey_info = { type: jsPsychHtmlKeyboardResponse, choices: [' '], stimulus: stimulusMap.get('pre_survey_info'), }; const ai_probe_row = { text: 'I believed that my partner was an AI agent or a bot.', value: 'SuspicionAI', } const exprimenter_probe_row = { text: 'I believed that my partner was an experimenter pretending to be a participant.', value: 'SuspicionExperimenter', } const survey_function = (survey) => { survey.onAfterRenderPage.add(function (sender, options) { console.log('Survey page rendered:', sender.currentPage); if (survey.activePage.name === 'page1') { 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 = { 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: probe_condition === 'ai' ? probe_text_ai : probe_text_human, alternateRows: true, isAllRowRequired: debug ? false : true, rows: [ { text: 'I believed that my partner was another participant.', value: 'ConfidencePartner', }, probe_order === 'ai_first' ? ai_probe_row : exprimenter_probe_row, { text: `There's no question here. Select 'Disagree' to show that you're paying attention.`, value: 'AttentionCheck', }, probe_order === 'ai_first' ? exprimenter_probe_row : ai_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: '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 factors = { selector: ['partner', 'participant'], together_side: ['left', 'right'], location: short_version ? [33, 50, 66] : [32, 33, 34, 49, 50, 51, 65, 66, 67], }; const practice_factors = { selector: ['partner', 'participant'], together_side: ['left', 'right'], location: [50], }; const trials = jsPsych.randomization.factorial(factors, 1); if (debug) { console.log(factors); console.log(trials); } const practice_trials = jsPsych.randomization.factorial(practice_factors, 1); const object_moving_trials = { timeline: [ { type: jsPsychObjectMoving, selector: jsPsych.timelineVariable('selector'), together_side: jsPsych.timelineVariable('together_side'), location: jsPsych.timelineVariable('location'), together_colour: together_colour, }, ], timeline_variables: trials, }; const object_moving_practice = { timeline: [ { type: jsPsychObjectMoving, selector: jsPsych.timelineVariable('selector'), together_side: jsPsych.timelineVariable('together_side'), location: jsPsych.timelineVariable('location'), together_colour: together_colour, }, ], timeline_variables: practice_trials, }; if (debug) { timeline.push(survey) timeline.push(debrief); } if (!debug) { timeline.push(pre_consent_info); timeline.push(consent_form); timeline.push(enter_fullscreen); timeline.push(multi_user_instructions); timeline.push(initial_lobby); timeline.push(instructions_1); timeline.push(instructions_2); timeline.push(instructions_3); timeline.push(instructions_4); timeline.push(pre_practice_instructions); timeline.push(lobby_slow); timeline.push(object_moving_practice); timeline.push(pre_task_instructions); timeline.push(lobby_fast); timeline.push(object_moving_trials); timeline.push(pre_survey_info); timeline.push(survey); timeline.push(debrief); } jsPsych.run(timeline);