Compare commits

..

2 Commits

Author SHA1 Message Date
Shaheed Azaad
6893fae173 removed WWU 2025-07-02 00:14:19 +02:00
Shaheed Azaad
9460d6247c added timer to survey 2025-07-02 00:10:11 +02:00
7 changed files with 1113 additions and 86 deletions

View File

@@ -1,6 +0,0 @@
VITE_DEBUG=true
VITE_COMPLETE_URL=
VITE_CLOSED_URL=
VITE_EXPERIMENT_TITLE=
VITE_EXPERIMENT_NAME=
VITE_DEPLOY_URL=

View File

@@ -1,6 +0,0 @@
VITE_DEBUG=false
VITE_COMPLETE_URL=
VITE_CLOSED_URL=
VITE_EXPERIMENT_TITLE=
VITE_EXPERIMENT_NAME=
VITE_DEPLOY_URL=

180
index.js
View File

@@ -10,16 +10,18 @@ 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 debug = import.meta.env.VITE_DEBUG === 'true';
const total_participants = import.meta.env.VITE_TOTAL_PARTICIPANTS;
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; // P in the params, O = open, S = suspicion mentioned
let mapping; // M in the params, TB = together blue, AB = alone blue
let short_version = false;
let debug = false;
const short_version = true; // just using the short version of the task
function delayed_redirect(url) {
setTimeout(() => {
@@ -28,51 +30,68 @@ function delayed_redirect(url) {
}
const jsPsych = initJsPsych({
on_finish: function() {
on_finish: function () {
jsPsych.getDisplayElement().innerHTML = textStimuli.complete;
},
on_close: function() {
on_close: function () {
delayed_redirect(import.meta.env.VITE_CLOSED_URL);
},
on_data_update: function() {
on_data_update: function () {
if (debug) {
console.log(jsPsych.data.get().json());
}
},
});
prolific_id = jsPsych.data.getURLVariable('PROLIFIC_PID');
mapping = jsPsych.data.getURLVariable('M');
short_version = jsPsych.data.getURLVariable('S') === 'true';
const together_colour = mapping === 'TB' ? 'blue' : 'red';
const stimulusMap = getStimulusMap(together_colour);
debug = jsPsych.data.getURLVariable('debug') === 'true';
probe_condition = jsPsych.data.getURLVariable('P');
prolific_id = jsPsych.data.getURLVariable('PROLIFIC_PID');
const COND = Number(jsPsych.data.getURLVariable('C'));
const probe_text_direct = 'Did you have any thoughts, observations, or suspicions about the experiment?'
const probe_text_indirect = 'Did you have any thoughts or observations about the experiment?';
let together_colour;
let probe_text;
if (probe_condition === 'O') {
probe_text =
'Did you have any thoughts or observations about the experiment?';
} else if (probe_condition === 'S') {
probe_text =
'Did you have any thoughts, observations, or suspicions about the experiment?';
} else if (probe_condition === 'D') {
probe_text =
'Many studies use deception to create the appearance that you are interacting with a real person. Did you suspect that you were not interacting with a real person?';
} else if (probe_condition === 'R') {
probe_text =
'Our study used deception to create the appearance that you are interacting with a real person. Did you suspect that you were not interacting with a real person?';
} else {
probe_text =
'Did you have any thoughts or observations about the experiment?';
switch (COND) {
case 0:
probe_condition = 'direct';
together_colour = 'blue';
break;
case 1:
probe_condition = 'direct';
together_colour = 'red';
break;
case 2:
probe_condition = 'indirect';
together_colour = 'blue';
break;
case 3:
probe_condition = 'indirect';
together_colour = 'red';
break;
}
jsPsych.data.addProperties({
probe_text = probe_condition === 'direct' ? probe_text_direct : probe_text_indirect;
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_text,
});
}
if (debug) {
console.log(props);
}
jsPsych.data.addProperties(props);
const timeline = [];
@@ -91,7 +110,7 @@ const consent_form = {
type: jsPsychHtmlButtonResponse,
stimulus: stimulusMap.get('consent'),
choices: ['Exit', 'Continue'],
on_finish: function(data) {
on_finish: function (data) {
if (data.response === 0) {
jsPsych.abortExperiment(stimulusMap.get('no_consent'));
}
@@ -176,8 +195,39 @@ const debrief = {
stimulus: stimulusMap.get('debrief'),
};
const pre_survey_info = {
type: jsPsychHtmlKeyboardResponse,
choices: [' '],
stimulus: stimulusMap.get('pre_survey_info'),
};
const survey_function = (survey) => {
survey.onAfterRenderPage.add(function (sender, options) {
if (survey.activePage.name === 'page1') {
const nextButton = document.querySelector('#sv-nav-next > div > input');
if (nextButton) {
let seconds = 30;
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);
}
console.log('Survey page rendered:', sender.currentPage);
}
});
}
const survey = {
type: jsPsychSurvey,
survey_function: survey_function,
survey_json: {
showQuestionNumbers: false,
completeText: 'Done!',
@@ -187,48 +237,18 @@ const survey = {
pages: [
{
name: 'page1',
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,
},
],
},
{
name: 'page2',
elements: [
{
type: 'comment',
title: probe_text,
description: 'You may continue to the next page after 30 seconds.',
name: 'probe',
isRequired: debug ? false : true,
},
],
},
{
name: 'page3',
name: 'page2',
elements: [
{
type: 'matrix',
@@ -271,6 +291,37 @@ const survey = {
},
],
},
{
name: 'page1',
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,
},
],
}
],
},
};
@@ -323,8 +374,8 @@ const object_moving_practice = {
};
if (debug) {
timeline.push(survey);
timeline.push(debrief);
}
if (!debug) {
@@ -343,6 +394,7 @@ if (!debug) {
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);
}

961
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -14,8 +14,13 @@
"vite": "^6.3.1"
},
"dependencies": {
"@jspsych/plugin-fullscreen": "^2.1.0",
"@jspsych/plugin-html-button-response": "^2.1.0",
"@jspsych/plugin-html-keyboard-response": "^2.1.0",
"@jspsych/plugin-survey": "^2.1.0",
"@tailwindcss/vite": "^4.1.4",
"archiver": "^7.0.1",
"dotenv": "^17.0.1",
"jspsych": "^8.2.1",
"prettier-plugin-html-template-literals": "^1.0.5",
"tailwindcss": "^4.1.4",

View File

@@ -160,9 +160,9 @@ class jsPsychObjectMoving {
}
function initiate_partner_action(){
const go_delay = trial.selector === 'participant' ? 1200 : 800
const partner_go_delay = jsPsych.randomization.sampleExGaussian(go_delay, 300, 1/100, true);
const partner_teleport_delay = jsPsych.randomization.sampleExGaussian(1200, 200, 1/100, true);
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);

View File

@@ -15,10 +15,15 @@ const redImages = {
instructions_4: '/images/red/instructions_4.png',
};
const html = (strings, ...values) =>
strings
.reduce((result, str, i) => result + str + (values[i] || ''), '')
.trim();
import html from '../utils/html.js';
export const textStimuli = {
complete: html`Experiment complete. Please paste the following link into your browser to confirm completion on Prolific:
<span class="text-blue-500">
${import.meta.env.VITE_COMPLETE_URL}
</a>
`,
};
function getStimulusMap(together_colour) {
const colourMap = getColourMap(together_colour);
@@ -28,6 +33,23 @@ function getStimulusMap(together_colour) {
// Select the appropriate image map based on the color
const imageMap = together_colour === 'blue' ? blueImages : redImages;
stimulusMap.set('pre_survey_info', html`
<p class="leading-relaxed">
You will now answer a few questions about your experience in the experiment. It is important that you read the questions carefully and answer them honestly.
</p>
<p class ="leading-relaxed mt-2">
Nonsense or random answers may lead to your submission being rejected.
</p>
<p class="mt-6">
Press
<strong>SPACE</strong>
to continue.
</p>
`
);
stimulusMap.set(
'pre_consent_info',
html`
@@ -104,14 +126,13 @@ function getStimulusMap(together_colour) {
</p>
The controller within the meaning of the EU General Data Protection
Regulation (GDPR) and other national data protection laws of the member
states, as well as other data protection regulations is the Westfälische
Wilhelms-Universität Münster (WWU), represented by the Rector, Prof. Dr.
states, as well as other data protection regulations is the University of Muenster, represented by the Rector, Prof. Dr.
Johannes Wessels, Schlossplatz 2, 48149 MünsterTel.: + 49 251
83-0E-Mail: verwaltung@uni-muenster.de
<p class="font-semibold mt-2">
8. Contact details of the data protection officer
</p>
The data protection officer of the WWU Münster is: Nina Meyer-Pachur
The data protection officer of the University of Muenster is: Nina Meyer-Pachur
Schlossplatz 2, 48149 Münster Tel.: + 49 251 83-22446 E-Mail:
datenschutz@uni-muenster.de
<p class="font-semibold mt-2">