Files
suspicion-checks-experiment-3/index.js
2025-07-02 21:32:05 +02:00

430 lines
12 KiB
JavaScript

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 = 'experimenter';
together_colour = 'blue';
probe_order = 'ai_first';
break;
case 3:
probe_condition = 'experimenter';
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 = 'experimenter';
together_colour = 'blue';
probe_order = 'human_first';
break;
case 7:
probe_condition = 'experimenter';
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_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 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);