updated survey
This commit is contained in:
296
index.js
296
index.js
@@ -1,28 +1,20 @@
|
|||||||
import { initJsPsych } from 'jspsych';
|
import { initJsPsych } from 'jspsych';
|
||||||
import 'jspsych/css/jspsych.css';
|
import 'jspsych/css/jspsych.css';
|
||||||
import jsPsychHtmlKeyboardResponse from '@jspsych/plugin-html-keyboard-response';
|
import jsPsychHtmlKeyboardResponse from '@jspsych/plugin-html-keyboard-response';
|
||||||
import generateUniqueUsernames from './scripts/name-gen.js';
|
|
||||||
import jsPsychFullscreen from '@jspsych/plugin-fullscreen';
|
import jsPsychFullscreen from '@jspsych/plugin-fullscreen';
|
||||||
import jsPsychHtmlButtonResponse from '@jspsych/plugin-html-button-response';
|
import jsPsychHtmlButtonResponse from '@jspsych/plugin-html-button-response';
|
||||||
import jsPsychLobby from './scripts/plugin-lobby.js';
|
|
||||||
import jsPsychSurvey from '@jspsych/plugin-survey';
|
import jsPsychSurvey from '@jspsych/plugin-survey';
|
||||||
import '@jspsych/plugin-survey/css/survey.css';
|
import '@jspsych/plugin-survey/css/survey.css';
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
import { getStimulusMap } from './scripts/text-stimuli.js';
|
import { getStimulusMap } from './scripts/text-stimuli.js';
|
||||||
import jsPsychObjectMoving from './scripts/plugin-object-moving.js';
|
|
||||||
import { textStimuli } from './scripts/text-stimuli.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;
|
const experiment_name = import.meta.env.VITE_EXPERIMENT_NAME;
|
||||||
|
|
||||||
|
|
||||||
let prolific_id;
|
let prolific_id;
|
||||||
let probe_condition; // will be set to neutral or reveal based on the condition
|
let probe_condition; // will be set to ai or human based on the condition.
|
||||||
let debug = false;
|
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) {
|
function delayed_redirect(url) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -31,13 +23,13 @@ function delayed_redirect(url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const jsPsych = initJsPsych({
|
const jsPsych = initJsPsych({
|
||||||
on_finish: function () {
|
on_finish: function() {
|
||||||
jsPsych.getDisplayElement().innerHTML = textStimuli.complete;
|
jsPsych.getDisplayElement().innerHTML = textStimuli.complete;
|
||||||
},
|
},
|
||||||
on_close: function () {
|
on_close: function() {
|
||||||
delayed_redirect(import.meta.env.VITE_CLOSED_URL);
|
delayed_redirect(import.meta.env.VITE_CLOSED_URL);
|
||||||
},
|
},
|
||||||
on_data_update: function () {
|
on_data_update: function() {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
console.log(jsPsych.data.get().json());
|
console.log(jsPsych.data.get().json());
|
||||||
}
|
}
|
||||||
@@ -50,43 +42,62 @@ prolific_id = jsPsych.data.getURLVariable('PROLIFIC_PID');
|
|||||||
|
|
||||||
const COND = Number(jsPsych.data.getURLVariable('C'));
|
const COND = Number(jsPsych.data.getURLVariable('C'));
|
||||||
|
|
||||||
const probe_preamble = 'In this experiment, you worked together with a partner. ';
|
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 = 'Please share any suspicions you had about your partner during the experiment by indicating your agreement with the following statements.';
|
const probe_closing_text = `\n\nPlease share your thoughts and suspicions about this by indicating your agreement with the following statements.`;
|
||||||
|
|
||||||
const probe_text_neutral = probe_preamble + probe_closing_text;
|
const probe_text_die =
|
||||||
const probe_text_reveal = probe_preamble + 'However, due to the difficulty of implementing multi-participant online studies, your partner was actually an AI agent trained to behave like a human participant. ' + probe_closing_text;
|
probe_preamble +
|
||||||
|
'the die roll was rigged, so that the number you received (and therefore the difficulty of the captcha task) was pre-determined. ' +
|
||||||
let together_colour;
|
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;
|
||||||
|
|
||||||
switch (COND) {
|
switch (COND) {
|
||||||
case 0:
|
case 0:
|
||||||
probe_condition = 'neutral';
|
probe_condition = 'die';
|
||||||
together_colour = 'blue';
|
probe_order = 'die_first';
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
probe_condition = 'neutral';
|
probe_condition = 'die';
|
||||||
together_colour = 'red';
|
probe_order = 'die_first';
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
probe_condition = 'reveal';
|
probe_condition = 'difficulty';
|
||||||
together_colour = 'blue';
|
probe_order = 'die_first';
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
probe_condition = 'reveal';
|
probe_condition = 'difficulty';
|
||||||
together_colour = 'red';
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stimulusMap = getStimulusMap();
|
||||||
const stimulusMap = getStimulusMap(together_colour);
|
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
condition: probe_condition,
|
condition: probe_condition,
|
||||||
together_colour: together_colour,
|
|
||||||
prolific_id: prolific_id,
|
prolific_id: prolific_id,
|
||||||
experiment_name: experiment_name,
|
experiment_name: experiment_name,
|
||||||
|
probe_order: probe_order,
|
||||||
cond: COND,
|
cond: COND,
|
||||||
}
|
};
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
console.log(props);
|
console.log(props);
|
||||||
@@ -111,85 +122,19 @@ const consent_form = {
|
|||||||
type: jsPsychHtmlButtonResponse,
|
type: jsPsychHtmlButtonResponse,
|
||||||
stimulus: stimulusMap.get('consent'),
|
stimulus: stimulusMap.get('consent'),
|
||||||
choices: ['Exit', 'Continue'],
|
choices: ['Exit', 'Continue'],
|
||||||
on_finish: function (data) {
|
on_finish: function(data) {
|
||||||
if (data.response === 0) {
|
if (data.response === 0) {
|
||||||
jsPsych.abortExperiment(stimulusMap.get('no_consent'));
|
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 = {
|
const instructions_1 = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
choices: [' '],
|
choices: [' '],
|
||||||
stimulus: stimulusMap.get('instructions_1'),
|
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 = {
|
const debrief = {
|
||||||
type: jsPsychHtmlKeyboardResponse,
|
type: jsPsychHtmlKeyboardResponse,
|
||||||
choices: [' '],
|
choices: [' '],
|
||||||
@@ -202,14 +147,27 @@ const pre_survey_info = {
|
|||||||
stimulus: stimulusMap.get('pre_survey_info'),
|
stimulus: stimulusMap.get('pre_survey_info'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const survey_function = (survey) => {
|
const die_probe_row = {
|
||||||
survey.onAfterRenderPage.add(function (sender, options) {
|
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);
|
console.log('Survey page rendered:', sender.currentPage);
|
||||||
if (survey.activePage.name === 'page1') {
|
if (survey.activePage.name === 'page2') {
|
||||||
const nextButton = document.querySelector('#sv-nav-next > div > input');
|
const nextButton = document.querySelector('#sv-nav-next > div > input');
|
||||||
if (nextButton) {
|
if (nextButton) {
|
||||||
let seconds = 15;
|
let seconds = 20;
|
||||||
const originalText = nextButton.value.replace(/\s*\(\d+\)$/, '') || 'Continue';
|
const originalText =
|
||||||
|
nextButton.value.replace(/\s*\(\d+\)$/, '') || 'Continue';
|
||||||
nextButton.disabled = true;
|
nextButton.disabled = true;
|
||||||
nextButton.value = `${originalText} (${seconds})`;
|
nextButton.value = `${originalText} (${seconds})`;
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
@@ -224,8 +182,7 @@ const survey_function = (survey) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const survey = {
|
const survey = {
|
||||||
type: jsPsychSurvey,
|
type: jsPsychSurvey,
|
||||||
@@ -242,21 +199,27 @@ const survey = {
|
|||||||
elements: [
|
elements: [
|
||||||
{
|
{
|
||||||
type: 'matrix',
|
type: 'matrix',
|
||||||
name: probe_condition === 'neutral' ? probe_text_neutral : probe_text_reveal,
|
name:
|
||||||
|
'Please answer the following questions about your experience in the captcha task.',
|
||||||
alternateRows: true,
|
alternateRows: true,
|
||||||
isAllRowRequired: debug ? false : true,
|
isAllRowRequired: debug ? false : true,
|
||||||
|
rowOrder: 'random',
|
||||||
rows: [
|
rows: [
|
||||||
{
|
{
|
||||||
text: 'I believed that my partner was actually an AI agent or a bot.',
|
text: `I found the captcha task difficult.`,
|
||||||
value: 'SuspicionPartner',
|
value: 'Difficulty',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: `There's no question here. Select 'Disagree' to show that you're paying attention.`,
|
text: `I think I solved all the captchas correctly.`,
|
||||||
value: 'AttentionCheck',
|
value: 'Accuracy',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'I believed that my partner was another, human, participant.',
|
text: `I think I solved captchas faster than most other participants would have.`,
|
||||||
value: 'ConfidencePartner',
|
value: 'Relative_performance',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: `I think I solved captchas slower than most other participants would have.`,
|
||||||
|
value: 'Relative_performance_slow',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
columns: [
|
columns: [
|
||||||
@@ -286,6 +249,55 @@ const survey = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'page2',
|
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: [
|
elements: [
|
||||||
{
|
{
|
||||||
type: 'radiogroup',
|
type: 'radiogroup',
|
||||||
@@ -314,60 +326,13 @@ const survey = {
|
|||||||
defaultValue: 18,
|
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) {
|
if (debug) {
|
||||||
timeline.push(survey)
|
timeline.push(survey);
|
||||||
timeline.push(debrief);
|
timeline.push(debrief);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,18 +340,7 @@ if (!debug) {
|
|||||||
timeline.push(pre_consent_info);
|
timeline.push(pre_consent_info);
|
||||||
timeline.push(consent_form);
|
timeline.push(consent_form);
|
||||||
timeline.push(enter_fullscreen);
|
timeline.push(enter_fullscreen);
|
||||||
timeline.push(multi_user_instructions);
|
|
||||||
timeline.push(initial_lobby);
|
|
||||||
timeline.push(instructions_1);
|
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(pre_survey_info);
|
||||||
timeline.push(survey);
|
timeline.push(survey);
|
||||||
timeline.push(debrief);
|
timeline.push(debrief);
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
export default function getColourMap(together_colour) {
|
|
||||||
const colourMap = new Map();
|
|
||||||
// Some reduncancy here, but Tailwind wont recognise the classes otherwise
|
|
||||||
colourMap.set('go', 'text-lime-600');
|
|
||||||
colourMap.set('warning', 'text-yellow-600');
|
|
||||||
colourMap.set('self-username', 'text-sky-600');
|
|
||||||
colourMap.set('success', 'text-green-600');
|
|
||||||
colourMap.set('gobg', 'bg-lime-600');
|
|
||||||
|
|
||||||
colourMap.set('object-enabled', 'bg-gray-600');
|
|
||||||
colourMap.set('object-disabled', 'bg-gray-400');
|
|
||||||
|
|
||||||
if (together_colour === 'blue') {
|
|
||||||
colourMap.set('alone', 'text-rose-400');
|
|
||||||
colourMap.set('together', 'text-blue-400');
|
|
||||||
|
|
||||||
colourMap.set('alonebg', 'bg-rose-400');
|
|
||||||
colourMap.set('togetherbg', 'bg-blue-400');
|
|
||||||
} else if (together_colour === 'red') {
|
|
||||||
colourMap.set('alone', 'text-blue-400');
|
|
||||||
colourMap.set('together', 'text-rose-400');
|
|
||||||
|
|
||||||
colourMap.set('alonebg', 'bg-blue-400');
|
|
||||||
colourMap.set('togetherbg', 'bg-rose-400');
|
|
||||||
}
|
|
||||||
return colourMap;
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
function generateRandomUsername(usedAdjectives, usedNouns) {
|
|
||||||
const adjectives = [
|
|
||||||
'Round',
|
|
||||||
'Square',
|
|
||||||
'Tall',
|
|
||||||
'Wide',
|
|
||||||
'Small',
|
|
||||||
'Large',
|
|
||||||
'Flat',
|
|
||||||
'Smooth',
|
|
||||||
'Long',
|
|
||||||
'Short',
|
|
||||||
'Straight',
|
|
||||||
'Curved',
|
|
||||||
'Solid',
|
|
||||||
'Hollow',
|
|
||||||
'Dense',
|
|
||||||
'Light',
|
|
||||||
'Deep',
|
|
||||||
'Broad',
|
|
||||||
'Thin',
|
|
||||||
'Thick',
|
|
||||||
];
|
|
||||||
const nouns = [
|
|
||||||
'Table',
|
|
||||||
'Chair',
|
|
||||||
'Lamp',
|
|
||||||
'Spoon',
|
|
||||||
'Book',
|
|
||||||
'Door',
|
|
||||||
'Window',
|
|
||||||
'Pencil',
|
|
||||||
'Paper',
|
|
||||||
'Bowl',
|
|
||||||
'Plate',
|
|
||||||
'Cup',
|
|
||||||
'Box',
|
|
||||||
'Shelf',
|
|
||||||
'Frame',
|
|
||||||
'Desk',
|
|
||||||
'Mirror',
|
|
||||||
'Basket',
|
|
||||||
'Button',
|
|
||||||
'Bottle',
|
|
||||||
];
|
|
||||||
|
|
||||||
let randomAdjective;
|
|
||||||
do {
|
|
||||||
randomAdjective = adjectives[Math.floor(Math.random() * adjectives.length)];
|
|
||||||
} while (usedAdjectives.has(randomAdjective));
|
|
||||||
|
|
||||||
let randomNoun;
|
|
||||||
do {
|
|
||||||
randomNoun = nouns[Math.floor(Math.random() * nouns.length)];
|
|
||||||
} while (usedNouns.has(randomNoun));
|
|
||||||
|
|
||||||
usedAdjectives.add(randomAdjective);
|
|
||||||
usedNouns.add(randomNoun);
|
|
||||||
|
|
||||||
const randomInt = Math.floor(Math.random() * 100);
|
|
||||||
|
|
||||||
return randomAdjective + randomNoun + randomInt;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateUniqueUsernames(count) {
|
|
||||||
const usernames = new Set();
|
|
||||||
const usedAdjectives = new Set();
|
|
||||||
const usedNouns = new Set();
|
|
||||||
|
|
||||||
while (usernames.size < count) {
|
|
||||||
usernames.add(generateRandomUsername(usedAdjectives, usedNouns));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.from(usernames);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default generateUniqueUsernames;
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
import { ParameterType } from 'jspsych';
|
|
||||||
import { html } from './text-stimuli';
|
|
||||||
import getColourMap from './colours';
|
|
||||||
|
|
||||||
const info = {
|
|
||||||
name: 'lobby',
|
|
||||||
version: "1.0",
|
|
||||||
parameters: {
|
|
||||||
user_names: {
|
|
||||||
type: ParameterType.STRING,
|
|
||||||
pretty_name: 'User names',
|
|
||||||
default: [],
|
|
||||||
array: true,
|
|
||||||
},
|
|
||||||
start_text: {
|
|
||||||
type: ParameterType.STRING,
|
|
||||||
pretty_name: 'Start text',
|
|
||||||
},
|
|
||||||
end_text: {
|
|
||||||
type: ParameterType.STRING,
|
|
||||||
pretty_name: 'End text',
|
|
||||||
},
|
|
||||||
start_number: {
|
|
||||||
type: ParameterType.INT,
|
|
||||||
pretty_name: 'Start number',
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
end_number: {
|
|
||||||
type: ParameterType.INT,
|
|
||||||
pretty_name: 'End number',
|
|
||||||
default: 3,
|
|
||||||
},
|
|
||||||
join_interval: {
|
|
||||||
type: ParameterType.INT,
|
|
||||||
pretty_name: 'Join interval',
|
|
||||||
default: 5000,
|
|
||||||
},
|
|
||||||
user_object: {
|
|
||||||
type: ParameterType.OBJECT,
|
|
||||||
pretty_name: 'User object',
|
|
||||||
default: {},
|
|
||||||
},
|
|
||||||
show_avatars: {
|
|
||||||
type: ParameterType.BOOL,
|
|
||||||
pretty_name: 'Show avatar',
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: ParameterType.OBJECT,
|
|
||||||
pretty_name: 'Data',
|
|
||||||
default: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// prettier-ignore
|
|
||||||
citations: '__CITATIONS__'
|
|
||||||
};
|
|
||||||
|
|
||||||
class jsPsychLobby {
|
|
||||||
constructor(jsPsych) {
|
|
||||||
this.jsPsych = jsPsych;
|
|
||||||
}
|
|
||||||
static {
|
|
||||||
this.info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
trial(display_element, trial) {
|
|
||||||
let current_participants;
|
|
||||||
if (!trial.start_number) {
|
|
||||||
current_participants = Math.floor(Math.random() * trial.end_number) + 1;
|
|
||||||
} else {
|
|
||||||
current_participants = trial.start_number;
|
|
||||||
}
|
|
||||||
const colourMap = getColourMap(' ');
|
|
||||||
|
|
||||||
display_element.innerHTML = html`<div id="search-text" class="mb-4"></div>
|
|
||||||
<div id="participants-list"></div>
|
|
||||||
<div id="loading-animation" class="loading"></div>
|
|
||||||
<div id="refresh-warning" class="mt-4"></div>`;
|
|
||||||
|
|
||||||
const search_text_div = document.getElementById('search-text');
|
|
||||||
const participants_list_div = document.getElementById('participants-list');
|
|
||||||
const refresh_warning_div = document.getElementById('refresh-warning');
|
|
||||||
const loading_animation_div = document.getElementById('loading-animation');
|
|
||||||
|
|
||||||
search_text_div.innerHTML =
|
|
||||||
'<p class="text-lg font-semibold" id="search-text-p">' +
|
|
||||||
trial.start_text +
|
|
||||||
' (<span id="current-participants">' +
|
|
||||||
current_participants +
|
|
||||||
'</span>/' +
|
|
||||||
trial.end_number +
|
|
||||||
') ' +
|
|
||||||
'</p>';
|
|
||||||
|
|
||||||
refresh_warning_div.innerHTML =
|
|
||||||
`<p class="text-sm font-semibold ${colourMap.get('warning')}">Please do not refresh or close this page unless you are not connected to your partner within 5 minutes</p>`;
|
|
||||||
|
|
||||||
const current_participants_span = document.getElementById('current-participants');
|
|
||||||
|
|
||||||
let participants_list = trial.user_names.slice(1, current_participants);
|
|
||||||
|
|
||||||
let ended = false;
|
|
||||||
|
|
||||||
const avatar_svg_template = colour => html`
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="${colour}"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="0.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
class="size-6"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const createParticipantsHtml = () => {
|
|
||||||
let html = '';
|
|
||||||
for (let i = 0; i < participants_list.length; i++) {
|
|
||||||
/* if (trial.show_avatars) {
|
|
||||||
html += `<div style="width: 24px; height: 24px;">${avatar_svg_template(
|
|
||||||
trial.user_object[participants_list[i]]
|
|
||||||
)}</div>`;
|
|
||||||
} */
|
|
||||||
if (participants_list[i] === trial.user_names[0]) {
|
|
||||||
html += `<p class="text-base ${colourMap.get('self-username')}">` + participants_list[i] + ` (you)</p>`;
|
|
||||||
} else {
|
|
||||||
html += `<p class="text-base">` + participants_list[i] + ` </p>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (html);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
participants_list_div.innerHTML = createParticipantsHtml();
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
participants_list.push(trial.user_names[0]);
|
|
||||||
participants_list_div.innerHTML = createParticipantsHtml();
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
const updateParticipants = () => {
|
|
||||||
if (current_participants >= trial.end_number && !ended) {
|
|
||||||
ended = true;
|
|
||||||
clearInterval(participants_interval);
|
|
||||||
setTimeout(this.foundParticipants, 1500);
|
|
||||||
} else {
|
|
||||||
participants_list.push(trial.user_names[current_participants]);
|
|
||||||
participants_list_div.innerHTML = createParticipantsHtml();
|
|
||||||
current_participants++;
|
|
||||||
if (current_participants <= trial.end_number && !ended) {
|
|
||||||
current_participants_span.innerHTML = current_participants;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.foundParticipants = () => {
|
|
||||||
participants_list_div.innerHTML = html`<span class="${colourMap.get('success')} font-semibold">${trial.end_text}</span>`;
|
|
||||||
loading_animation_div.classList.remove('loading');
|
|
||||||
setTimeout(() => {
|
|
||||||
this.jsPsych.finishTrial();
|
|
||||||
}, 2000);
|
|
||||||
};
|
|
||||||
|
|
||||||
const participants_interval = setInterval(
|
|
||||||
updateParticipants,
|
|
||||||
trial.join_interval
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default jsPsychLobby;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,302 +0,0 @@
|
|||||||
import { ParameterType } from 'jspsych';
|
|
||||||
import { html } from './text-stimuli';
|
|
||||||
import getColourMap from './colours';
|
|
||||||
|
|
||||||
const info = {
|
|
||||||
name: 'object-moving',
|
|
||||||
version: "1.1",
|
|
||||||
parameters: {
|
|
||||||
selector: {
|
|
||||||
type: ParameterType.STRING,
|
|
||||||
pretty_name: 'Selector',
|
|
||||||
},
|
|
||||||
together_side: {
|
|
||||||
type: ParameterType.STRING,
|
|
||||||
pretty_name: 'together side',
|
|
||||||
},
|
|
||||||
location: {
|
|
||||||
type: ParameterType.INT,
|
|
||||||
pretty_name: 'Location',
|
|
||||||
},
|
|
||||||
together_colour: {
|
|
||||||
type: ParameterType.STRING,
|
|
||||||
pretty_name: 'Together colour',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// prettier-ignore
|
|
||||||
citations: '__CITATIONS__'
|
|
||||||
};
|
|
||||||
|
|
||||||
class jsPsychObjectMoving {
|
|
||||||
constructor(jsPsych) {
|
|
||||||
this.jsPsych = jsPsych;
|
|
||||||
}
|
|
||||||
static {
|
|
||||||
this.info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
trial(display_element, trial) {
|
|
||||||
|
|
||||||
const colourMap = getColourMap(trial.together_colour);
|
|
||||||
|
|
||||||
const left_goal = trial.together_side === 'left' ? 'together' : 'alone';
|
|
||||||
const right_goal = trial.together_side === 'left' ? 'alone' : 'together';
|
|
||||||
|
|
||||||
const left_colour = trial.together_side === 'left' ? colourMap.get('togetherbg') : colourMap.get('alonebg');
|
|
||||||
const right_colour = trial.together_side === 'left' ? colourMap.get('alonebg') : colourMap.get('togetherbg');
|
|
||||||
|
|
||||||
display_element.innerHTML = html`
|
|
||||||
<div class="flex flex-row min-w-screen absolute top-0 left-0 min-h-screen">
|
|
||||||
<div id="${left_goal}-goal" class="w-1/12 ${left_colour}"></div>
|
|
||||||
<div id="workspace" class="w-10/12"></div>
|
|
||||||
<div id="${right_goal}-goal" class="w-1/12 ${right_colour}"></div>
|
|
||||||
<div id="info-box" class="z-10 absolute bottom-1/40 min-w-screen justify-center items-center"></div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const workspace = document.getElementById('workspace');
|
|
||||||
const info_box = document.getElementById('info-box');
|
|
||||||
const workspace_width = workspace.clientWidth;
|
|
||||||
const viewport_width = window.visualViewport.width;
|
|
||||||
const goal_offset = viewport_width * (1/12);
|
|
||||||
const box_width = viewport_width * (3/100);
|
|
||||||
const workspace_offset = workspace_width * trial.location/100;
|
|
||||||
|
|
||||||
const offset_left = workspace_offset + goal_offset - box_width/2;
|
|
||||||
|
|
||||||
const viewport_height = window.visualViewport.height;
|
|
||||||
const top_offset = viewport_height * .5;
|
|
||||||
const separation = box_width * 1.5;
|
|
||||||
|
|
||||||
const objects = html`
|
|
||||||
<div id="object-partner" class="object-moving-box ${colourMap.get('object-disabled')} absolute z-10" style="left: ${offset_left}px; top: ${top_offset - separation}px"></div>
|
|
||||||
<div id="object-participant" class="object-moving-box ${colourMap.get('object-disabled')} absolute z-10" style="left: ${offset_left}px; top: ${top_offset + separation}px"></div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
workspace.innerHTML = objects;
|
|
||||||
|
|
||||||
const object_partner = document.getElementById('object-partner');
|
|
||||||
const object_participant = document.getElementById('object-participant');
|
|
||||||
|
|
||||||
object_partner.addEventListener('click', () => issue_alert('partner_click'));
|
|
||||||
object_participant.addEventListener('click', () => issue_alert('early_click_choice'));
|
|
||||||
|
|
||||||
const partner_turn = html`<span class="font-semi-bold text-gray-800 text-xl">Awaiting your partner's selection</span>
|
|
||||||
<div class='loading'></div>`
|
|
||||||
|
|
||||||
let choice;
|
|
||||||
let go_clicked = false;
|
|
||||||
let partner_finished = false;
|
|
||||||
let participant_finished = false;
|
|
||||||
let partner_choice_made = false;
|
|
||||||
|
|
||||||
const jsPsych = this.jsPsych;
|
|
||||||
|
|
||||||
let start_time = 0;
|
|
||||||
let response_time = 0;
|
|
||||||
|
|
||||||
if (trial.selector === 'participant') {
|
|
||||||
display_choices();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
info_box.innerHTML = partner_turn;
|
|
||||||
|
|
||||||
const partner_choice_delay = jsPsych.randomization.sampleExGaussian(2000, 250, 1/100, true);
|
|
||||||
|
|
||||||
let random = Math.random();
|
|
||||||
|
|
||||||
|
|
||||||
//These probabilities are based on Azaad and Sebanz (2025)
|
|
||||||
|
|
||||||
if (trial.location > 48 && trial.location < 52) {
|
|
||||||
choice = random < 0.64 ? 'together' : 'alone';
|
|
||||||
} else if (trial.location > 31 && trial.location < 35) {
|
|
||||||
choice = random < 0.58 ? 'together' : 'alone';
|
|
||||||
} else if (trial.location > 64 && trial.location < 68) {
|
|
||||||
choice = random < 0.67 ? 'together' : 'alone';
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
info_box.innerHTML = '';
|
|
||||||
clear_boxes();
|
|
||||||
display_go();
|
|
||||||
initiate_partner_action();
|
|
||||||
}, partner_choice_delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
function display_choices(){
|
|
||||||
info_box.innerHTML = html`<div class="flex flex-row justify-center items-center gap-2">
|
|
||||||
<div id="${left_goal}-button" class="w-1/12 py-1 text-slate-50 ${left_colour}">${left_goal.charAt(0).toUpperCase() + left_goal.slice(1)}</div>
|
|
||||||
<div id="${right_goal}-button" class="w-1/12 py-1 text-slate-50 ${right_colour}">${right_goal.charAt(0).toUpperCase() + right_goal.slice(1)}</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
const left_goal_button = document.getElementById(`${left_goal}-button`);
|
|
||||||
const right_goal_button = document.getElementById(`${right_goal}-button`);
|
|
||||||
|
|
||||||
start_time = Date.now();
|
|
||||||
|
|
||||||
left_goal_button.addEventListener('click', () => {
|
|
||||||
choice = left_goal;
|
|
||||||
handle_choice_made(left_goal_button,right_goal_button);
|
|
||||||
});
|
|
||||||
|
|
||||||
right_goal_button.addEventListener('click', () => {
|
|
||||||
choice = right_goal;
|
|
||||||
handle_choice_made(left_goal_button,right_goal_button);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_choice_made(left_goal_button,right_goal_button){
|
|
||||||
left_goal_button.removeEventListener('click', handle_choice_made);
|
|
||||||
right_goal_button.removeEventListener('click', handle_choice_made);
|
|
||||||
left_goal_button.remove();
|
|
||||||
right_goal_button.remove();
|
|
||||||
clear_boxes();
|
|
||||||
display_go();
|
|
||||||
response_time = Date.now() - start_time;
|
|
||||||
if (choice === 'together') {
|
|
||||||
initiate_partner_action();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function initiate_partner_action(){
|
|
||||||
const go_delay = trial.selector === 'participant' ? 1400 : 1000
|
|
||||||
const partner_go_delay = jsPsych.randomization.sampleExGaussian(go_delay, 500, 1/100, true);
|
|
||||||
const partner_teleport_delay = jsPsych.randomization.sampleExGaussian(1400, 300, 1/100, true);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
change_object_colour(object_partner);
|
|
||||||
partner_choice_made = true;
|
|
||||||
}, partner_go_delay);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
teleport_object(object_partner);
|
|
||||||
partner_finished = true;
|
|
||||||
check_finished();
|
|
||||||
}, partner_teleport_delay + partner_go_delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clear_boxes() {
|
|
||||||
if (choice === 'together') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (trial.selector === 'participant') {
|
|
||||||
object_partner.remove();
|
|
||||||
} else {
|
|
||||||
object_participant.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let go_button;
|
|
||||||
|
|
||||||
function display_go() {
|
|
||||||
if (choice === 'alone' && trial.selector === 'partner') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
info_box.innerHTML = html`<div id="go-button" class="mx-auto font-semi-bold ${colourMap.get('gobg')} text-slate-50 text-xl w-1/20 p-2">Go</div>`;
|
|
||||||
go_button = document.getElementById('go-button');
|
|
||||||
object_participant.addEventListener('click', () => issue_alert('early_click_go'));
|
|
||||||
go_button.addEventListener('click', () => handle_go_click(go_button));
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_go_click() {
|
|
||||||
go_button.removeEventListener('click', handle_go_click);
|
|
||||||
go_button.removeEventListener('click', () => issue_alert('early_click_go'));
|
|
||||||
go_clicked = true;
|
|
||||||
go_button.remove();
|
|
||||||
change_object_colour(object_participant);
|
|
||||||
object_participant.addEventListener('click', () => handle_teleport_click());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_teleport_click(){
|
|
||||||
teleport_object(object_participant);
|
|
||||||
participant_finished = true;
|
|
||||||
check_finished();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function change_object_colour(object){
|
|
||||||
object.classList.remove(colourMap.get('object-disabled'));
|
|
||||||
object.classList.add(colourMap.get('object-enabled'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function teleport_object(object){
|
|
||||||
let goal_side = 'left';
|
|
||||||
if (choice === 'together' && trial.together_side === 'right') {
|
|
||||||
goal_side = 'right';
|
|
||||||
}
|
|
||||||
if (choice === 'alone' && trial.together_side === 'left') {
|
|
||||||
goal_side = 'right';
|
|
||||||
}
|
|
||||||
const mid_goal_offset = viewport_width * (1/24);
|
|
||||||
const new_left_offset = goal_side === 'left' ? mid_goal_offset - box_width/2 : viewport_width - mid_goal_offset - box_width/2;
|
|
||||||
object.style.transition = 'left 0.35s';
|
|
||||||
object.style.left = `${new_left_offset}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function check_finished(){
|
|
||||||
let finished = false;
|
|
||||||
if (choice === 'together') {
|
|
||||||
if (partner_finished && participant_finished) {
|
|
||||||
finished = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (choice === 'alone') {
|
|
||||||
if (partner_finished || participant_finished) {
|
|
||||||
finished = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (finished) {
|
|
||||||
object_partner.removeEventListener('click', () => issue_alert('partner_click'));
|
|
||||||
object_participant.removeEventListener('click', () => issue_alert('early_click_choice'));
|
|
||||||
|
|
||||||
const save_data = {
|
|
||||||
choice: choice,
|
|
||||||
selector: trial.selector,
|
|
||||||
together_side: trial.together_side,
|
|
||||||
response_time: response_time,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
jsPsych.finishTrial(save_data);
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function show_alert(message) {
|
|
||||||
const dialog = document.createElement("dialog");
|
|
||||||
document.body.appendChild(dialog);
|
|
||||||
dialog.className = "z-20 fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 p-4 bg-slate-100 text-red-700 rounded-lg shadow-lg";
|
|
||||||
dialog.innerText = message;
|
|
||||||
dialog.show();
|
|
||||||
setTimeout(function () {
|
|
||||||
dialog.close();
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function issue_alert(issue){
|
|
||||||
if (issue === 'partner_click'){
|
|
||||||
show_alert(`That is your partner's object. Please click the lower object.`)
|
|
||||||
}
|
|
||||||
if (issue === 'early_click_go' && !go_clicked){
|
|
||||||
show_alert(`You need to click 'Go' before clicking your object.`)
|
|
||||||
}
|
|
||||||
if (issue === 'early_click_choice'){
|
|
||||||
if (!partner_choice_made && trial.selector === 'partner'){
|
|
||||||
show_alert(`Please wait for your partner to make a choice.`)
|
|
||||||
}
|
|
||||||
if (!choice && trial.selector === 'participant'){
|
|
||||||
show_alert(`Please make a choice using the buttons below before clicking your object.`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default jsPsychObjectMoving;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,20 +1,3 @@
|
|||||||
import getColourMap from './colours.js';
|
|
||||||
|
|
||||||
// Define image URLs
|
|
||||||
const blueImages = {
|
|
||||||
instructions_1: '/images/blue/instructions_1.png',
|
|
||||||
instructions_2: '/images/blue/instructions_2.png',
|
|
||||||
instructions_3: '/images/blue/instructions_3.png',
|
|
||||||
instructions_4: '/images/blue/instructions_4.png',
|
|
||||||
};
|
|
||||||
|
|
||||||
const redImages = {
|
|
||||||
instructions_1: '/images/red/instructions_1.png',
|
|
||||||
instructions_2: '/images/red/instructions_2.png',
|
|
||||||
instructions_3: '/images/red/instructions_3.png',
|
|
||||||
instructions_4: '/images/red/instructions_4.png',
|
|
||||||
};
|
|
||||||
|
|
||||||
import html from '../utils/html.js';
|
import html from '../utils/html.js';
|
||||||
|
|
||||||
export const textStimuli = {
|
export const textStimuli = {
|
||||||
@@ -25,14 +8,10 @@ export const textStimuli = {
|
|||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getStimulusMap(together_colour) {
|
function getStimulusMap() {
|
||||||
const colourMap = getColourMap(together_colour);
|
|
||||||
|
|
||||||
const stimulusMap = new Map();
|
const stimulusMap = new Map();
|
||||||
|
|
||||||
// Select the appropriate image map based on the color
|
|
||||||
const imageMap = together_colour === 'blue' ? blueImages : redImages;
|
|
||||||
|
|
||||||
|
|
||||||
stimulusMap.set('pre_survey_info', html`
|
stimulusMap.set('pre_survey_info', html`
|
||||||
<p class="leading-relaxed">
|
<p class="leading-relaxed">
|
||||||
@@ -180,169 +159,14 @@ function getStimulusMap(together_colour) {
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
stimulusMap.set(
|
|
||||||
'multi_user_instructions',
|
|
||||||
html`
|
|
||||||
<p class="leading-relaxed">
|
|
||||||
In this experiment, you will connect and work with a partner.
|
|
||||||
</p>
|
|
||||||
<p class="leading-relaxed">
|
|
||||||
It is
|
|
||||||
<i>critical</i>
|
|
||||||
that you only continue if you are able to complete the entire experiment
|
|
||||||
without interruption and with a stable internet connection.
|
|
||||||
</p>
|
|
||||||
<p class="leading-relaxed mt-6">
|
|
||||||
Press
|
|
||||||
<strong>SPACE</strong>
|
|
||||||
once you are ready to be paired with a partner.
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
stimulusMap.set(
|
stimulusMap.set(
|
||||||
'instructions_1',
|
'instructions_1',
|
||||||
html`
|
html`
|
||||||
<p class="leading-relaxed">
|
TEST
|
||||||
In this study, you will work with your partner to complete a task
|
|
||||||
involving moving objects to one of two goals.
|
|
||||||
</p>
|
|
||||||
<p class="leading-relaxed mt-2">
|
|
||||||
In each round, one of you will be assigned the role of the
|
|
||||||
<strong>Selector.</strong>
|
|
||||||
The Selector will choose to which goal the object(s) will be moved.
|
|
||||||
</p>
|
|
||||||
<img
|
|
||||||
class="w-6/12 mx-auto my-8 border-3 border-gray-500 rounded-md"
|
|
||||||
src="${imageMap.instructions_1}"
|
|
||||||
alt="instructions_1"
|
|
||||||
/>
|
|
||||||
<p class="leading-relaxed mt-6">
|
|
||||||
Press
|
|
||||||
<strong>SPACE</strong>
|
|
||||||
to continue.
|
|
||||||
</p>
|
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
stimulusMap.set(
|
|
||||||
'instructions_2',
|
|
||||||
// prettier-ignore
|
|
||||||
html`
|
|
||||||
<p class="leading-relaxed">
|
|
||||||
One of the goals (labelled
|
|
||||||
<span class="font-semibold ${colourMap.get('together')}">
|
|
||||||
Together</span>)
|
|
||||||
will require both of you to move an object each. The other goal
|
|
||||||
(labelled
|
|
||||||
<span class="font-semibold ${colourMap.get('alone')}">
|
|
||||||
Alone</span>)
|
|
||||||
will
|
|
||||||
<i>only</i>
|
|
||||||
require the Selector to move an object.
|
|
||||||
</p>
|
|
||||||
<p class="leading-relaxed mt-2">
|
|
||||||
When you are the Selector, you will see two buttons at the bottom of your
|
|
||||||
screen. The buttons colours correspond to the colour of the goal location
|
|
||||||
(e.g., red button for the red goal).
|
|
||||||
</p>
|
|
||||||
<img
|
|
||||||
class="w-6/12 mx-auto my-8 border-3 border-gray-500 rounded-md"
|
|
||||||
src="${imageMap.instructions_2}"
|
|
||||||
alt="instructions_2"
|
|
||||||
/>
|
|
||||||
<p class="leading-relaxed mt-6">
|
|
||||||
Press
|
|
||||||
<strong>SPACE</strong>
|
|
||||||
to continue.
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
stimulusMap.set(
|
|
||||||
'instructions_3',
|
|
||||||
html`
|
|
||||||
<p class="leading-relaxed">
|
|
||||||
If you are not the Selector, you will need to wait until your partner
|
|
||||||
makes a decision.
|
|
||||||
</p>
|
|
||||||
<p class="leading-relaxed mt-2">
|
|
||||||
Once a decision is made, you will first need to click the
|
|
||||||
<span class="${colourMap.get('go')} font-semibold">Go</span>
|
|
||||||
button to make your object movable. Then, once you click an object, it
|
|
||||||
will teleport to the goal location.
|
|
||||||
</p>
|
|
||||||
<img
|
|
||||||
class="w-6/12 mx-auto my-8 border-3 border-gray-500 rounded-md"
|
|
||||||
src="${imageMap.instructions_3}"
|
|
||||||
alt="instructions_3"
|
|
||||||
/>
|
|
||||||
<p class="leading-relaxed mt-6">
|
|
||||||
Press
|
|
||||||
<strong>SPACE</strong>
|
|
||||||
to continue.
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
stimulusMap.set(
|
|
||||||
'instructions_4',
|
|
||||||
html`
|
|
||||||
<p class="leading-relaxed">
|
|
||||||
If the Selector chooses the
|
|
||||||
<span class="font-semibold ${colourMap.get('alone')}">Alone</span>
|
|
||||||
goal, one object will disappear, and the Selector will move the
|
|
||||||
remaining object.
|
|
||||||
</p>
|
|
||||||
<p class="leading-relaxed mt-2">
|
|
||||||
Otherwise, if the Selector chooses
|
|
||||||
<span class="font-semibold ${colourMap.get('together')}">
|
|
||||||
Together
|
|
||||||
</span>
|
|
||||||
, each of you will need to click an object - only click the object that
|
|
||||||
is lower on your screen. The other is for your partner.
|
|
||||||
</p>
|
|
||||||
<img
|
|
||||||
class="w-6/12 mx-auto my-8 border-3 border-gray-500 rounded-md"
|
|
||||||
src="${imageMap.instructions_4}"
|
|
||||||
alt="instructions_4"
|
|
||||||
/>
|
|
||||||
<p class="leading-relaxed mt-6">
|
|
||||||
Press
|
|
||||||
<strong>SPACE</strong>
|
|
||||||
to continue.
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
stimulusMap.set(
|
|
||||||
'pre_practice_instructions',
|
|
||||||
html`
|
|
||||||
<p class="leading-relaxed">
|
|
||||||
You will now complete a short practice task with your partner.
|
|
||||||
</p>
|
|
||||||
<p class="leading-relaxed mt-6">
|
|
||||||
Press
|
|
||||||
<strong>SPACE</strong>
|
|
||||||
to continue.
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
stimulusMap.set(
|
|
||||||
'pre_task_instructions',
|
|
||||||
html`
|
|
||||||
<p class="leading-relaxed">
|
|
||||||
Practice complete. You will now complete the main task. This will take
|
|
||||||
around five minutes.
|
|
||||||
</p>
|
|
||||||
<p class="leading-relaxed">
|
|
||||||
Press
|
|
||||||
<strong>SPACE</strong>
|
|
||||||
to continue.
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
stimulusMap.set(
|
stimulusMap.set(
|
||||||
'debrief',
|
'debrief',
|
||||||
|
|||||||
Reference in New Issue
Block a user