Files
suspicion-checks-experiment-3/index.js
2026-02-20 00:49:20 +01:00

425 lines
11 KiB
JavaScript

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';
console.log('debug:', debug);
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 would roll a die to determine the difficulty of the captcha task.\nHowever, `;
const probe_closing_text = `\n\nPlease share your thoughts and suspicions about this by indicating your agreement with the following statements.`;
const probe_text_die =
probe_preamble +
'the die roll was rigged, so that the number you received (and therefore the difficulty of the captcha task) was pre-determined. ' +
probe_closing_text;
const probe_text_difficulty =
probe_preamble +
'while the die roll was random, the difficulty of the captcha task was pre-determined and unrelated to the die roll. ' +
probe_closing_text;
let die_result = 3;
switch (COND) {
case 0:
probe_condition = 'die';
probe_order = 'die_first';
die_result = 4;
break;
case 1:
probe_condition = 'die';
probe_order = 'die_first';
die_result = 4;
break;
case 2:
probe_condition = 'difficulty';
probe_order = 'die_first';
die_result = 4;
break;
case 3:
probe_condition = 'difficulty';
probe_order = 'die_first';
die_result = 4;
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;
}
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_trial = {
type: JsPsychDieRoll,
prompt: html`
<p class="mt-2">
Click the die once to start it rolling, then click it again to stop.
</p>
`,
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:
'<p class="leading-relaxed text-center">Enter the characters you see into the textbox below.</p>',
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 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 = {
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 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 felt lucky during the die roll.`,
value: 'Luck',
},
{
text: `I felt unlucky during the die roll.`,
value: 'Bad_luck',
},
{
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',
},
],
},
],
},
{
name: 'page2',
elements: [
{
type: 'matrix',
name:
probe_condition === 'die'
? probe_text_die
: probe_text_difficulty,
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: '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_trial,
instructions_3,
...captcha_trials,
pre_survey_info,
survey,
debrief,
];
if (debug) {
timeline.push(...main_experiment_timeline);
}
if (!debug) {
timeline.push(pre_consent_info);
timeline.push(consent_form);
timeline.push(enter_fullscreen);
timeline.push(...main_experiment_timeline);
}
jsPsych.run(timeline);