1927 lines
62 KiB
Plaintext
1927 lines
62 KiB
Plaintext
## Response Requirement
|
||
|
||
**Every AI response must start with:**
|
||
"Inshallah lets start"
|
||
|
||
**Modal Identification:**
|
||
At the beginning of each response, identify the current AI model being used by stating its official name.
|
||
|
||
---
|
||
|
||
## 🎯 Core Test Specifications
|
||
|
||
### Test Structure (CRITICAL)
|
||
- **Practice Phase:** 20 trials (adolescents) or 25 trials (adults) with feedback
|
||
- **Main Test Phase:** 15 memory sets across 5 triads
|
||
- **Adolescents:** 5 triads of (1-letter, 3-letter, 5-letter) = 650 probe trials total
|
||
- **Adults:** 5 triads of (2-pair, 4-pair, 6-pair) = 800 probe trials total
|
||
- **Total Test:** Practice + Main (670 or 825 total probe trials)
|
||
- **Timing:**
|
||
- Fixation cross: 0.3s (300ms)
|
||
- Memory set item display: 1.1s (adolescents) / 1.3s (adults) per item
|
||
- Retention interval: 1.0s (1000ms)
|
||
- Probe display: 6.0s (adolescents) / 4.5s (adults) per probe
|
||
- Feedback (practice only): 1.0s (correct) / 1.5s (incorrect) / 1.0s (timeout)
|
||
- Inter-trial interval: 0.3s (300ms) recommended
|
||
- **Probe Types:**
|
||
- **Positive probes:** Item WAS in memory set (correct answer: Yes)
|
||
- **Negative probes:** Item was NOT in memory set (correct answer: No)
|
||
|
||
### Age Groups
|
||
|
||
#### 1. **Adolescents (14-18 years):**
|
||
- **Stimuli:** Single letters only (A-Z)
|
||
- **Memory set sizes:** 1, 3, 5 letters
|
||
- **Probe response time:** 6 seconds per probe
|
||
- **Memory item display:** 1.1 seconds per letter
|
||
- **Practice:** 1-letter span (K) with 20 probe trials
|
||
- **Main task:** 5 triads alternating 1→3→5 letter spans
|
||
- **Probe distribution per span:**
|
||
- 1-letter: 30 probes per set
|
||
- 3-letter: 50 probes per set
|
||
- 5-letter: 50 probes per set
|
||
- **Total main probes:** 650 trials
|
||
- **Instructions:** Casual, encouraging, game-like language
|
||
- **Example:** Memory set = [A, D, F] → Probe = D → Answer: Yes (positive)
|
||
|
||
#### 2. **Adults (18-22 years):**
|
||
- **Stimuli:** Alphanumeric pairs (Letter + Number, e.g., K7, C9, R2)
|
||
- **Memory set sizes:** 2, 4, 6 pairs
|
||
- **Probe response time:** 4.5 seconds per probe
|
||
- **Memory item display:** 1.3 seconds per pair
|
||
- **Practice:** 2-pair span (C9, B3) with 25 probe trials
|
||
- **Main task:** 5 triads alternating 2→4→6 pair spans
|
||
- **Probe distribution per span:**
|
||
- 2-pair: 30 probes per set
|
||
- 4-pair: 65 probes per set
|
||
- 6-pair: 65 probes per set
|
||
- **Total main probes:** 800 trials
|
||
- **Instructions:** Formal, concise, professional language
|
||
- **Example:** Memory set = [K7, C9] → Probe = C9 → Answer: Yes (positive)
|
||
|
||
---
|
||
|
||
## 🔑 Critical Implementation Rules
|
||
|
||
### Core Task Concept (HIGHEST PRIORITY)
|
||
|
||
```javascript
|
||
// WORKING MEMORY TASK: Serial Recognition Paradigm
|
||
|
||
// PHASE 1: ENCODING (Memory Set Presentation)
|
||
// Items shown sequentially, one at a time
|
||
// Adolescent example: A → D → F (each for 1.1s)
|
||
// Adult example: K7 → C9 → R2 (each for 1.3s)
|
||
// Participant must MEMORIZE these items during presentation
|
||
|
||
// PHASE 2: RETENTION INTERVAL
|
||
// Blank screen for 1 second
|
||
// Participant holds items in working memory (no external cues)
|
||
// Critical for measuring active maintenance
|
||
|
||
// PHASE 3: RECOGNITION (Probe Trials)
|
||
// Single items shown one at a time
|
||
// Participant decides: "Was this item in the memory set?"
|
||
//
|
||
// POSITIVE PROBE (Target): Item WAS in set
|
||
// Example: Memory set = [A, D, F], Probe = D
|
||
// Correct answer: YES
|
||
//
|
||
// NEGATIVE PROBE (Non-Target): Item was NOT in set
|
||
// Example: Memory set = [A, D, F], Probe = G
|
||
// Correct answer: NO
|
||
|
||
// PHASE 4: REPEAT PROBES
|
||
// All probes for current memory set are tested
|
||
// Then move to next memory set
|
||
// Continue until all 15 memory sets complete
|
||
|
||
// KEY MEASURE: Accuracy and Reaction Time across different memory loads
|
||
// Larger memory sets → Greater cognitive load → Performance decline
|
||
```
|
||
|
||
### Memory Set Presentation Rules
|
||
|
||
```javascript
|
||
// Sequential Presentation (CRITICAL):
|
||
// - Items appear ONE AT A TIME (never all at once)
|
||
// - Each item displays for fixed duration (1.1s or 1.3s)
|
||
// - No overlap between items
|
||
// - Blank screen between items (optional, use fixation or immediate next)
|
||
|
||
// Display Requirements:
|
||
// - Centered on screen
|
||
// - Large, clear font (text-4xl or text-5xl)
|
||
// - White text on black background
|
||
// - High contrast for easy reading
|
||
|
||
// Adolescent Display:
|
||
// - Single letters: A, B, C, D, E, F, G, etc.
|
||
// - Uppercase only
|
||
// - Display duration: 1.1 seconds per letter
|
||
|
||
// Adult Display:
|
||
// - Alphanumeric pairs: A1, B2, C3, K7, etc.
|
||
// - Letter (uppercase) + Number (1-9)
|
||
// - Display duration: 1.3 seconds per pair
|
||
```
|
||
|
||
### Probe Trial Distribution
|
||
|
||
```javascript
|
||
// CRITICAL: Predetermined sequences (NOT randomized)
|
||
// Follow exact probe order from PDF for both age groups
|
||
|
||
// Adolescent Practice (1-letter span: K):
|
||
// - Total probes: 20
|
||
// - Positive probes (K): 10 trials
|
||
// - Negative probes (A, M, R, L, B, T, C, D, S, F): 10 trials
|
||
// - Probe sequence must match PDF exactly
|
||
|
||
// Adult Practice (2-pair span: C9, B3):
|
||
// - Total probes: 25
|
||
// - Positive probes (C9 or B3): 13 trials
|
||
// - Negative probes (A1, D4, F2, H8, K7, L1, etc.): 12 trials
|
||
// - Probe sequence must match PDF exactly
|
||
|
||
// Main Task Structure:
|
||
// - 15 memory sets total (5 triads)
|
||
// - Each triad contains one set of each span size
|
||
// - Alternating pattern: Small → Medium → Large
|
||
// - Adolescents: 1 → 3 → 5 letters (repeated 5 times)
|
||
// - Adults: 2 → 4 → 6 pairs (repeated 5 times)
|
||
|
||
// Probe counts per memory set:
|
||
// Adolescents:
|
||
// 1-letter sets: 30 probes each
|
||
// 3-letter sets: 50 probes each
|
||
// 5-letter sets: 50 probes each
|
||
// Adults:
|
||
// 2-pair sets: 30 probes each
|
||
// 4-pair sets: 65 probes each
|
||
// 6-pair sets: 65 probes each
|
||
```
|
||
|
||
### Response Handling (CRITICAL)
|
||
|
||
```javascript
|
||
// Response Method:
|
||
// - Two buttons: "Yes" and "No"
|
||
// - Position: Centered at bottom of screen
|
||
// - Always visible during probe display
|
||
// - Button styling: White border, white text on black background
|
||
|
||
// Response Logic:
|
||
// - Click "Yes" if probe was in memory set (Positive/Target)
|
||
// - Click "No" if probe was NOT in memory set (Negative/Non-Target)
|
||
|
||
// Response Window:
|
||
// - Adolescents: 6000ms (6 seconds) from probe onset
|
||
// - Adults: 4500ms (4.5 seconds) from probe onset
|
||
// - Accept ONLY first response (prevent double-clicks)
|
||
// - Highlight selected button with light blue border immediately
|
||
|
||
// Response Recording:
|
||
// - Record WHICH button pressed ("Yes" or "No")
|
||
// - Record reaction time (RT) from probe onset to button press
|
||
// - Record accuracy (1 = correct, 0 = incorrect)
|
||
// - Record timestamp of response
|
||
|
||
// Timeout Handling:
|
||
// - If no response within window → "Time is up!" message (1 second)
|
||
// - Record as: participantResponse = "No Response"
|
||
// - Record accuracy = 0 (incorrect)
|
||
// - Record reactionTime = null (do NOT include in RT calculations)
|
||
```
|
||
|
||
### Feedback Rules (PRACTICE ONLY)
|
||
|
||
```javascript
|
||
// Practice Phase Feedback:
|
||
|
||
1. Correct Response (Positive probe + "Yes" OR Negative probe + "No"):
|
||
→ Display: "Correct! You remembered it right."
|
||
→ Duration: 1 second
|
||
→ Style: White text, centered, bold
|
||
|
||
2. Incorrect Response (Positive probe + "No" OR Negative probe + "Yes"):
|
||
→ Display: "That's okay—try to remember the set carefully."
|
||
→ Duration: 1.5 seconds
|
||
→ Style: White text, centered, bold
|
||
|
||
3. No Response (timeout):
|
||
→ Display: "Please press your choice quickly!"
|
||
→ Duration: 1 second
|
||
→ Style: White text, centered, bold
|
||
→ Optional: Soft alert tone
|
||
|
||
// Practice Block Feedback (After each practice session):
|
||
// - If accuracy ≥ 70%:
|
||
// "Great work! You're getting the hang of it."
|
||
// Duration: 2 seconds
|
||
//
|
||
// - If accuracy < 70%:
|
||
// "Let's try again! Focus and respond a bit faster."
|
||
// Duration: 2 seconds
|
||
|
||
// Main Test: NO FEEDBACK shown to participants
|
||
// - Only "Time is up!" on timeout
|
||
// - Light blue border on selected button is the only visual confirmation
|
||
// - All performance tracking happens silently in background
|
||
```
|
||
|
||
### Visual Feedback
|
||
|
||
```javascript
|
||
// On Response:
|
||
// - Selected button ("Yes" or "No") gets light blue border immediately
|
||
// - Border style: ring-4 ring-blue-400 (Tailwind CSS)
|
||
// - Border remains visible during feedback/transition
|
||
// - Clear visual confirmation of button press
|
||
|
||
// Timeout Display:
|
||
// - Full screen message: "Time is up!"
|
||
// - White text, bold, centered on black background
|
||
// - Display for 1 second
|
||
// - Then proceed to next probe/trial
|
||
```
|
||
|
||
---
|
||
|
||
## 🎨 Design Requirements
|
||
|
||
### Visual Design Principles
|
||
- **Clean, simple, high-contrast** - black background throughout entire test
|
||
- **Responsive:** 345px to large screens (mobile-first design)
|
||
- **Minimal animations** - no distracting effects during memory/probe phases
|
||
- **High visibility:** Centered stimuli, clear buttons, large readable fonts
|
||
- **Age-appropriate design:**
|
||
- **Adolescent:** Encouraging, game-like language ("Memory Challenge Game")
|
||
- **Adult:** Professional, clinical language ("Memory Challenge Game")
|
||
|
||
### Technology Stack
|
||
- **Framework:** React with JavaScript (jsx)
|
||
- **Styling:** Tailwind CSS only (core utilities only - no custom compiler)
|
||
- **Animations:** Framer Motion (minimal use - fade transitions only)
|
||
- **State Management:** React Hooks (useState, useEffect, useRef, useCallback, useMemo)
|
||
- **Timing:** performance.now() or Date.now() for precise RT measurement
|
||
|
||
### Stimulus Display Specifications
|
||
|
||
```javascript
|
||
// Memory Set Item Display:
|
||
// - Position: Center of screen
|
||
// - Font size: text-5xl or text-6xl (large, readable)
|
||
// - Font weight: bold
|
||
// - Color: White (#FFFFFF)
|
||
// - Background: Black (#000000)
|
||
// - Display duration: 1.1s (adolescent) / 1.3s (adult)
|
||
|
||
// Adolescent Stimuli:
|
||
// - Single uppercase letters: A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
|
||
// - Font: Clean sans-serif (default system font)
|
||
// - Example: "A" or "K" or "R"
|
||
|
||
// Adult Stimuli:
|
||
// - Alphanumeric pairs: Letter (A-Z) + Digit (1-9)
|
||
// - Format: {Letter}{Digit} with NO space (e.g., "K7", "C9", "B3")
|
||
// - Font: Clean sans-serif (default system font)
|
||
// - Example: "K7" or "C9" or "R2"
|
||
|
||
// Probe Display:
|
||
// - Same styling as memory set items
|
||
// - Position: Center of screen
|
||
// - Remain visible for full response window (6s or 4.5s)
|
||
// - Disappear after response OR timeout
|
||
|
||
// Response Buttons:
|
||
// - Two buttons: "Yes" and "No"
|
||
// - Position: Centered horizontally at bottom of screen
|
||
// - Spacing: Adequate gap between buttons (minimum 20px)
|
||
// - Button styling:
|
||
// - Border: 2px solid white (border-2 border-white)
|
||
// - Background: Transparent or dark gray
|
||
// - Text: White, bold, large (text-xl)
|
||
// - Padding: px-8 py-4 (touch-friendly)
|
||
// - Border radius: rounded-lg
|
||
// - Hover effect: Slight scale or brightness change
|
||
// - Selected: ring-4 ring-blue-400 (light blue border)
|
||
// - Minimum touch target: 44x44px (accessibility)
|
||
```
|
||
|
||
### Animation Standards
|
||
|
||
```javascript
|
||
// Minimal animations to maintain task integrity:
|
||
|
||
// Fixation Cross:
|
||
// - Simple fade in/out (duration: 200ms)
|
||
// - No complex motion
|
||
|
||
// Memory Set Items:
|
||
// - Instant appearance (no fade/scale)
|
||
// - Sharp onset for precise encoding timing
|
||
// - Instant disappearance
|
||
|
||
// Probe Items:
|
||
// - Instant appearance (no fade/scale)
|
||
// - Sharp onset for RT measurement accuracy
|
||
|
||
// Feedback (Practice):
|
||
// - Gentle fade in (duration: 200ms)
|
||
// - Fade out before next trial (duration: 200ms)
|
||
|
||
// Screen Transitions:
|
||
// - Simple fade between screens (duration: 300ms)
|
||
// - No sliding, scaling, or complex animations
|
||
|
||
// Button Interactions:
|
||
// - Immediate highlight on press (no delay)
|
||
// - Subtle scale on hover (scale: 1.02)
|
||
|
||
// DO NOT USE:
|
||
// - Complex entry/exit animations during task
|
||
// - Parallax effects
|
||
// - Particle effects
|
||
// - Distracting motion that could interfere with memory encoding
|
||
```
|
||
|
||
---
|
||
|
||
## 📱 Screen Flow (Sequential Development)
|
||
|
||
### Development Order (ONE SCREEN AT A TIME)
|
||
|
||
#### 1. IntroScreen ✅
|
||
**Purpose:** Welcome screen, age selection, task overview
|
||
|
||
**Components needed:**
|
||
- Age group selector (14-18 vs 18-22 radio buttons or buttons)
|
||
- Task title and brief explanation
|
||
- "Begin Test" / "Start" button
|
||
- Welcome header and instructions
|
||
|
||
**Required files:**
|
||
- `components/screens/VPSM/IntroScreen.jsx`
|
||
- `constants/vpsmInstructions.js`
|
||
|
||
**Key content:**
|
||
- **Title:** "Working Memory Challenge Game" (adolescent) or "Working Memory Assessment" (adult)
|
||
- **Brief explanation:** What is working memory, what participants will do
|
||
- **Age selection:** Clear buttons or options for 14-18 vs 18-22
|
||
- **Next step:** Transition to detailed instructions
|
||
|
||
**Adolescent Introduction:**
|
||
```
|
||
"Welcome to the Memory Challenge Game!
|
||
|
||
You will see a set of letters appear on the screen one by one.
|
||
After a short pause, you will be shown a letter and need to decide
|
||
whether it was part of the set you just saw.
|
||
|
||
If you saw it before, press Yes; if not, press No.
|
||
|
||
Take your time and try to respond as quickly as you can.
|
||
Don't worry if it seems tricky at first - we'll start with a few
|
||
practice rounds to get you ready."
|
||
```
|
||
|
||
**Adult Introduction:**
|
||
```
|
||
"Welcome to the Memory Challenge Game!
|
||
|
||
You will see sequences of letter-number pairs (for example: A1, C3)
|
||
appear on the screen one by one.
|
||
|
||
After a few seconds, you will be shown a series of letter-number pairs
|
||
and need to decide if it was part of the sequence you just saw.
|
||
|
||
If you saw it before, press Yes; if not, press No.
|
||
|
||
This is just a practice round, so relax and get used to how the game works!"
|
||
```
|
||
|
||
---
|
||
|
||
#### 2. PracticeInstructionsScreen ✅
|
||
**Purpose:** Detailed task instructions before practice
|
||
|
||
**Components needed:**
|
||
- Detailed task explanation
|
||
- Visual examples (optional diagrams/illustrations)
|
||
- Step-by-step trial flow explanation
|
||
- "Let's Go!" / "Begin Practice" button
|
||
|
||
**Required files:**
|
||
- `components/screens/VPSM/PracticeInstructionsScreen.jsx`
|
||
|
||
**Instructions Content:**
|
||
|
||
**Adolescents (14-18):**
|
||
```
|
||
"How the Memory Game Works:
|
||
|
||
1. REMEMBER: You'll see letters appear one by one (like A... D... F).
|
||
Watch carefully and try to remember all of them!
|
||
|
||
2. WAIT: There will be a short pause after the letters disappear.
|
||
|
||
3. DECIDE: You'll see ONE letter at a time and must answer:
|
||
- Was this letter in the set you just saw?
|
||
- Press YES if it was in the set
|
||
- Press NO if it was NOT in the set
|
||
|
||
Example:
|
||
- Memory set: A, D, F
|
||
- Probe shows "D" → Press YES ✓ (D was in the set)
|
||
- Probe shows "G" → Press NO ✓ (G was NOT in the set)
|
||
|
||
The number of letters may increase as you go, making it more challenging!
|
||
|
||
Ready to practice? When you're ready, tap 'Let's Go!' below."
|
||
```
|
||
|
||
**Adults (18-22):**
|
||
```
|
||
"Task Instructions:
|
||
|
||
1. ENCODING PHASE:
|
||
You will see letter-number pairs presented sequentially
|
||
(e.g., K7 → C9 → R2)
|
||
Memorize each pair as it appears
|
||
|
||
2. RETENTION INTERVAL:
|
||
Brief pause (1 second) - maintain items in memory
|
||
|
||
3. RECOGNITION PHASE:
|
||
Individual pairs will be shown one at a time
|
||
Decide: "Was this pair in the memory set?"
|
||
- Press YES if the pair was present (Target)
|
||
- Press NO if the pair was absent (Non-Target)
|
||
|
||
Example:
|
||
- Memory set: K7, C9, R2
|
||
- Probe: C9 → Correct response: YES (Target)
|
||
- Probe: A1 → Correct response: NO (Non-Target)
|
||
|
||
The memory load will increase throughout the task (2, 4, or 6 pairs).
|
||
|
||
When ready to begin practice, press 'Let's Go!' below."
|
||
```
|
||
|
||
---
|
||
|
||
#### 3. PracticeScreen ✅
|
||
**Purpose:** Practice trials with feedback to learn the task
|
||
|
||
**Components needed:**
|
||
- Fixation cross display (+)
|
||
- Memory set item display (sequential presentation)
|
||
- Retention interval (blank screen)
|
||
- Probe item display
|
||
- Two response buttons (Yes/No)
|
||
- Feedback display (practice only)
|
||
- Trial counter ("Trial 1/20" or "Trial 1/25")
|
||
- Response detection and timing system
|
||
|
||
**Required files:**
|
||
- `components/screens/VPSM/PracticeScreen.jsx`
|
||
- `components/shared/VPSM/MemorySetDisplay.jsx` (sequential item presentation)
|
||
- `components/shared/VPSM/ProbeDisplay.jsx` (single item + Yes/No buttons)
|
||
- `components/shared/VPSM/ResponseButtons.jsx` (Yes/No buttons)
|
||
- `components/shared/VPSM/FeedbackDisplay.jsx` (practice feedback)
|
||
- `components/shared/VPSM/FixationCross.jsx` (white + symbol)
|
||
- `hooks/vpsm/usePracticeScreen.js`
|
||
- `utils/vpsmTimer.js`
|
||
|
||
**Practice Trials (EXACT sequence from Research PDF):**
|
||
|
||
**Adolescents (20 trials, 1-letter span: K):**
|
||
```javascript
|
||
const ADOLESCENT_PRACTICE_TRIALS = [
|
||
{ trial: 1, memorySet: ['K'], probe: 'K', type: 'Positive', correctResponse: 'Yes', responseTime: 6 },
|
||
{ trial: 2, memorySet: ['K'], probe: 'A', type: 'Negative', correctResponse: 'No', responseTime: 6 },
|
||
{ trial: 3, memorySet: ['K'], probe: 'M', type: 'Negative', correctResponse: 'No', responseTime: 6 },
|
||
{ trial: 4, memorySet: ['K'], probe: 'K', type: 'Positive', correctResponse: 'Yes', responseTime: 6 },
|
||
{ trial: 5, memorySet: ['K'], probe: 'R', type: 'Negative', correctResponse: 'No', responseTime: 6 },
|
||
{ trial: 6, memorySet: ['K'], probe: 'K', type: 'Positive', correctResponse: 'Yes', responseTime: 6 },
|
||
{ trial: 7, memorySet: ['K'], probe: 'L', type: 'Negative', correctResponse: 'No', responseTime: 6 },
|
||
{ trial: 8, memorySet: ['K'], probe: 'B', type: 'Negative', correctResponse: 'No', responseTime: 6 },
|
||
{ trial: 9, memorySet: ['K'], probe: 'K', type: 'Positive', correctResponse: 'Yes', responseTime: 6 },
|
||
{ trial: 10, memorySet: ['K'], probe: 'K', type: 'Positive', correctResponse: 'Yes', responseTime: 6 },
|
||
{ trial: 11, memorySet: ['K'], probe: 'T', type: 'Negative', correctResponse: 'No', responseTime: 6 },
|
||
{ trial: 12, memorySet: ['K'], probe: 'C', type: 'Negative', correctResponse: 'No', responseTime: 6 },
|
||
{ trial: 13, memorySet: ['K'], probe: 'K', type: 'Positive', correctResponse: 'Yes', responseTime: 6 },
|
||
{ trial: 14, memorySet: ['K'], probe: 'K', type: 'Positive', correctResponse: 'Yes', responseTime: 6 },
|
||
{ trial: 15, memorySet: ['K'], probe: 'K', type: 'Positive', correctResponse: 'Yes', responseTime: 6 },
|
||
{ trial: 16, memorySet: ['K'], probe: 'D', type: 'Negative', correctResponse: 'No', responseTime: 6 },
|
||
{ trial: 17, memorySet: ['K'], probe: 'K', type: 'Positive', correctResponse: 'Yes', responseTime: 6 },
|
||
{ trial: 18, memorySet: ['K'], probe: 'S', type: 'Negative', correctResponse: 'No', responseTime: 6 },
|
||
{ trial: 19, memorySet: ['K'], probe: 'K', type: 'Positive', correctResponse: 'Yes', responseTime: 6 },
|
||
{ trial: 20, memorySet: ['K'], probe: 'F', type: 'Negative', correctResponse: 'No', responseTime: 6 }
|
||
];
|
||
```
|
||
|
||
**Adults (25 trials, 2-pair span: C9, B3):**
|
||
```javascript
|
||
const ADULT_PRACTICE_TRIALS = [
|
||
{ trial: 1, memorySet: ['C9', 'B3'], probe: 'C9', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 2, memorySet: ['C9', 'B3'], probe: 'A1', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 3, memorySet: ['C9', 'B3'], probe: 'B3', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 4, memorySet: ['C9', 'B3'], probe: 'D4', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 5, memorySet: ['C9', 'B3'], probe: 'F2', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 6, memorySet: ['C9', 'B3'], probe: 'C9', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 7, memorySet: ['C9', 'B3'], probe: 'H8', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 8, memorySet: ['C9', 'B3'], probe: 'B3', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 9, memorySet: ['C9', 'B3'], probe: 'K7', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 10, memorySet: ['C9', 'B3'], probe: 'C9', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 11, memorySet: ['C9', 'B3'], probe: 'B3', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 12, memorySet: ['C9', 'B3'], probe: 'L1', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 13, memorySet: ['C9', 'B3'], probe: 'D4', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 14, memorySet: ['C9', 'B3'], probe: 'C9', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 15, memorySet: ['C9', 'B3'], probe: 'B3', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 16, memorySet: ['C9', 'B3'], probe: 'F2', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 17, memorySet: ['C9', 'B3'], probe: 'C9', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 18, memorySet: ['C9', 'B3'], probe: 'B3', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 19, memorySet: ['C9', 'B3'], probe: 'H8', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 20, memorySet: ['C9', 'B3'], probe: 'A1', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 21, memorySet: ['C9', 'B3'], probe: 'C9', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 22, memorySet: ['C9', 'B3'], probe: 'B3', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 },
|
||
{ trial: 23, memorySet: ['C9', 'B3'], probe: 'K7', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 24, memorySet: ['C9', 'B3'], probe: 'D4', type: 'Negative', correctResponse: 'No', responseTime: 4.5 },
|
||
{ trial: 25, memorySet: ['C9', 'B3'], probe: 'C9', type: 'Positive', correctResponse: 'Yes', responseTime: 4.5 }
|
||
];
|
||
```
|
||
|
||
**Trial Flow (Complete Sequence):**
|
||
|
||
1. **Fixation Cross**
|
||
- Display: White "+" centered on black screen
|
||
- Duration: 300ms
|
||
- Purpose: Focus attention, prepare for encoding
|
||
|
||
2. **Memory Set Presentation** (CRITICAL - Sequential Display)
|
||
- Display each item ONE AT A TIME
|
||
- Adolescents: Each letter for 1.1 seconds
|
||
- Adults: Each alphanumeric pair for 1.3 seconds
|
||
- Items appear in sequence with NO overlap
|
||
- Example (3-letter): Show "A" (1.1s) → Show "F" (1.1s) → Show "R" (1.1s)
|
||
- Total encoding time = (number of items) × (display time per item)
|
||
|
||
3. **Retention Interval**
|
||
- Blank black screen
|
||
- Duration: 1 second (1000ms)
|
||
- Purpose: Active memory maintenance without external cues
|
||
|
||
4. **Probe Display + Response Window**
|
||
- Display: Single item centered + Yes/No buttons at bottom
|
||
- Adolescents: 6 seconds to respond
|
||
- Adults: 4.5 seconds to respond
|
||
- Accept ONLY first button press (prevent double-clicks)
|
||
- Highlight selected button with light blue border immediately
|
||
|
||
5. **Response Handling**
|
||
- If response given: Record button ("Yes"/"No"), RT, accuracy
|
||
- If timeout: Display "Time is up!" (1 second)
|
||
- Selected button shows light blue border
|
||
|
||
6. **Feedback Display (PRACTICE ONLY)**
|
||
- Correct: "Correct! You remembered it right." (1 second)
|
||
- Incorrect: "That's okay—try to remember the set carefully." (1.5 seconds)
|
||
- Timeout: "Please press your choice quickly!" (1 second, optional soft tone)
|
||
|
||
7. **Inter-trial Interval**
|
||
- Blank black screen
|
||
- Duration: 300ms
|
||
- Clear previous displays, prepare for next probe
|
||
|
||
8. **Next Probe or Next Memory Set**
|
||
- If more probes for current memory set: Go to step 1 (fixation for next probe)
|
||
- If all probes complete: Move to next memory set (start from step 1 with new memory set)
|
||
|
||
**Critical Rules:**
|
||
- Memory set shown ONCE at beginning, then all probes tested
|
||
- Show feedback after EACH probe trial in practice
|
||
- Track accuracy but don't show running score
|
||
- Exact timing is critical for valid RT measurement
|
||
|
||
---
|
||
|
||
#### 4. PracticeCompleteScreen ✅
|
||
**Purpose:** Transition from practice to main task
|
||
|
||
**Components needed:**
|
||
- Completion message
|
||
- Encouragement
|
||
- "Let's Go!" / "Begin Main Task" button
|
||
|
||
**Required files:**
|
||
- `components/screens/VPSM/PracticeCompleteScreen.jsx`
|
||
|
||
**Messages (from PDF):**
|
||
|
||
**Adolescents:**
|
||
```
|
||
"Great job finishing the practice! Now get ready for the real task.
|
||
Tap 'Let's Go!' below and the game begins!"
|
||
```
|
||
|
||
**Adults:**
|
||
```
|
||
"Great job finishing the practice! Now get ready for the real task.
|
||
Tap 'Let's Go!' below and the game begins!"
|
||
```
|
||
|
||
**Additional Information (Optional):**
|
||
- Don't show accuracy scores from practice
|
||
- Simple, encouraging transition
|
||
- Clear call-to-action button
|
||
|
||
---
|
||
|
||
#### 5. MainTestScreen ✅
|
||
**Purpose:** Main assessment - 15 memory sets across 5 triads
|
||
|
||
**Components needed:**
|
||
- All PracticeScreen components (except feedback display)
|
||
- NO feedback display (except timeout message)
|
||
- Progress tracking (Memory Set counter: "Set 1/15", optional probe counter)
|
||
- Data collection for all trials
|
||
- Continuous flow across all 15 memory sets
|
||
|
||
**Required files:**
|
||
- `components/screens/VPSM/MainTestScreen.jsx`
|
||
- `hooks/vpsm/useMainTestScreen.js`
|
||
- `utils/vpsmDataCollection.js`
|
||
- `constants/vpsmTrialSequences.js` (ALL main task trials from PDF)
|
||
|
||
**Main Task Structure:**
|
||
|
||
**Adolescents: 5 Triads, 15 Memory Sets, 650 Total Probes**
|
||
|
||
```javascript
|
||
// Triad 1 (Sets 1-3):
|
||
// Set 1: 1-letter (G) → 30 probes
|
||
// Set 2: 3-letter (A, F, R) → 50 probes
|
||
// Set 3: 5-letter (B, D, H, L, Q) → 50 probes
|
||
|
||
// Triad 2 (Sets 4-6):
|
||
// Set 4: 1-letter (E) → 30 probes
|
||
// Set 5: 3-letter (S, J, M) → 50 probes
|
||
// Set 6: 5-letter (F, N, I, R, V) → 50 probes
|
||
|
||
// Triad 3 (Sets 7-9):
|
||
// Set 7: 1-letter (K) → 30 probes
|
||
// Set 8: 3-letter (I, S, V) → 50 probes
|
||
// Set 9: 5-letter (B, X, E, S, O) → 50 probes
|
||
|
||
// Triad 4 (Sets 10-12):
|
||
// Set 10: 1-letter (U) → 30 probes
|
||
// Set 11: 3-letter (G, Q, T) → 50 probes
|
||
// Set 12: 5-letter (C, G, M, Q, W) → 50 probes
|
||
|
||
// Triad 5 (Sets 13-15):
|
||
// Set 13: 1-letter (M) → 30 probes
|
||
// Set 14: 3-letter (B, W, L) → 50 probes
|
||
// Set 15: 5-letter (H, L, P, T, Z) → 50 probes
|
||
|
||
// Total: (5 × 30) + (5 × 50) + (5 × 50) = 150 + 250 + 250 = 650 probes
|
||
```
|
||
|
||
**Adults: 5 Triads, 15 Memory Sets, 800 Total Probes**
|
||
|
||
```javascript
|
||
// Triad 1 (Sets 1-3):
|
||
// Set 1: 2-pair (B1, D3) → 30 probes
|
||
// Set 2: 4-pair (H6, J4, M2, R8) → 65 probes
|
||
// Set 3: 6-pair (F5, K9, L7, P3, T2, U6) → 65 probes
|
||
|
||
// Triad 2 (Sets 4-6):
|
||
// Set 4: 2-pair (C2, F4) → 30 probes
|
||
// Set 5: 4-pair (L8, Q1, G5, S3) → 65 probes
|
||
// Set 6: 6-pair (A7, D9, R6, U2, K3, V4) → 65 probes
|
||
|
||
// Triad 3 (Sets 7-9):
|
||
// Set 7: 2-pair (G1, E7) → 30 probes
|
||
// Set 8: 4-pair (N6, T4, P7, H9) → 65 probes
|
||
// Set 9: 6-pair (B5, C8, F2, J6, W3, Z1) → 65 probes
|
||
|
||
// Triad 4 (Sets 10-12):
|
||
// Set 10: 2-pair (J5, H2) → 30 probes
|
||
// Set 11: 4-pair (M8, Q5, K4, S7) → 65 probes
|
||
// Set 12: 6-pair (A3, C6, G8, L9, P2, Y5) → 65 probes
|
||
|
||
// Triad 5 (Sets 13-15):
|
||
// Set 13: 2-pair (K6, N3) → 30 probes
|
||
// Set 14: 4-pair (E4, G7, R1, T6) → 65 probes
|
||
// Set 15: 6-pair (B8, D2, F9, H5, X4, Z7) → 65 probes
|
||
|
||
// Total: (5 × 30) + (5 × 65) + (5 × 65) = 150 + 325 + 325 = 800 probes
|
||
```
|
||
|
||
**Main Task Instructions (Displayed before main task begins):**
|
||
|
||
**Adolescents:**
|
||
```
|
||
"Now it's time for the full game!
|
||
|
||
You will see a set of letters appear on the screen one by one.
|
||
After a short pause, you will see a series of letters and need to
|
||
decide whether it was part of the set you just saw.
|
||
|
||
Use the Yes or No buttons to make your choice.
|
||
|
||
The number of letters may gradually increase, making the game more challenging.
|
||
|
||
Stay sharp and have fun!"
|
||
```
|
||
|
||
**Adults:**
|
||
```
|
||
"Now it's time for the full game!
|
||
|
||
You will see a set of letter-number pairs appear on the screen one by one.
|
||
After a short pause, you will see a series of letter-number pairs and need
|
||
to decide whether it was part of the set you just saw.
|
||
|
||
Use the Yes or No buttons to make your choice.
|
||
|
||
The number of pairs may gradually increase, making the game more challenging.
|
||
|
||
Stay sharp and have fun!"
|
||
```
|
||
|
||
**Trial Flow (Same as practice, minus feedback):**
|
||
|
||
1. Fixation Cross (+): 300ms
|
||
2. Memory Set Presentation: Sequential items (1.1s or 1.3s each)
|
||
3. Retention Interval: 1 second blank screen
|
||
4. Probe Display + Buttons: 6s or 4.5s response window
|
||
5. Response Handling:
|
||
- Button press: Light blue border on selected button (only visual confirmation)
|
||
- Timeout: "Time is up!" (1 second)
|
||
6. Inter-trial Interval: 300ms black screen
|
||
7. Next Probe: Repeat steps 1-6 for all probes of current memory set
|
||
8. Next Memory Set: After all probes complete, move to next set
|
||
|
||
**Critical Differences from Practice:**
|
||
- NO feedback shown (except "Time is up!" on timeout)
|
||
- Light blue border is the ONLY response confirmation
|
||
- Track all metrics silently in background
|
||
- Show memory set progress (e.g., "Memory Set 3/15")
|
||
- Optional: Show probe progress within set (e.g., "Probe 12/50")
|
||
- Continuous flow - no breaks between sets unless designed
|
||
|
||
**Data Collection (Silent - No Display):**
|
||
- Record every probe trial response
|
||
- Calculate accuracy per memory set
|
||
- Calculate RT per memory set
|
||
- Track performance by span size (1/3/5 or 2/4/6)
|
||
- Identify patterns (speed-accuracy tradeoff, memory capacity limits)
|
||
|
||
---
|
||
|
||
#### 6. ResultsScreen ✅
|
||
**Purpose:** Display performance summary and export data
|
||
|
||
**Components needed:**
|
||
- Performance metrics display
|
||
- Accuracy breakdown (overall, by span size)
|
||
- Reaction time statistics (overall, by span size)
|
||
- Memory capacity analysis
|
||
- Data export functionality (JSON + CSV)
|
||
- Restart/Continue option
|
||
|
||
**Required files:**
|
||
- `components/screens/VPSM/ResultsScreen.jsx`
|
||
- `components/shared/VPSM/MetricsCard.jsx`
|
||
- `utils/vpsmCalculations.js`
|
||
- `utils/vpsmDataExport.js`
|
||
|
||
**Metrics to Calculate (from PDF Scoring Manual):**
|
||
|
||
```javascript
|
||
// RAW COUNTS:
|
||
// - Total Probe Trials: 650 (adolescent) or 800 (adult)
|
||
// - Total Rounds Answered: Count of trials with response
|
||
// - Total Rounds Not Answered: Count of timeouts
|
||
// - Correct Responses: Sum of trials with score = 1
|
||
// - Incorrect Responses: Sum of trials with score = 0
|
||
|
||
// ACCURACY METRICS (Percentage):
|
||
// Overall Accuracy:
|
||
// (Correct Responses / Total Probe Trials) × 100
|
||
|
||
// Accuracy by Span Size:
|
||
// Adolescents:
|
||
// 1-Letter Accuracy: (Correct 1-letter / Total 1-letter) × 100
|
||
// 3-Letter Accuracy: (Correct 3-letter / Total 3-letter) × 100
|
||
// 5-Letter Accuracy: (Correct 5-letter / Total 5-letter) × 100
|
||
|
||
// Adults:
|
||
// 2-Pair Accuracy: (Correct 2-pair / Total 2-pair) × 100
|
||
// 4-Pair Accuracy: (Correct 4-pair / Total 4-pair) × 100
|
||
// 6-Pair Accuracy: (Correct 6-pair / Total 6-pair) × 100
|
||
|
||
// REACTION TIME METRICS (Milliseconds):
|
||
// CRITICAL: Calculate RT ONLY for correctly answered trials
|
||
|
||
// Overall Mean RT:
|
||
// Average RT across ALL correct responses
|
||
|
||
// Mean RT by Span Size:
|
||
// Adolescents:
|
||
// 1-Letter Mean RT: Average RT for correct 1-letter trials
|
||
// 3-Letter Mean RT: Average RT for correct 3-letter trials
|
||
// 5-Letter Mean RT: Average RT for correct 5-letter trials
|
||
|
||
// Adults:
|
||
// 2-Pair Mean RT: Average RT for correct 2-pair trials
|
||
// 4-Pair Mean RT: Average RT for correct 4-pair trials
|
||
// 6-Pair Mean RT: Average RT for correct 6-pair trials
|
||
|
||
// MEMORY SPAN ANALYSIS:
|
||
// Working Memory Capacity Estimate:
|
||
// Highest span size where accuracy ≥ 75%
|
||
// Example: If 3-letter accuracy = 82% but 5-letter accuracy = 68%
|
||
// → Estimated capacity = 3 items
|
||
|
||
// RT Slope Analysis:
|
||
// Measure increase in RT as memory load increases
|
||
// Slope = (RT_large - RT_small) / (span_large - span_small)
|
||
// Example: (RT_5letter - RT_1letter) / (5 - 1)
|
||
// Indicates search strategy: Serial vs. Parallel processing
|
||
|
||
// ADDITIONAL METRICS:
|
||
// Response Bias:
|
||
// Proportion of "Yes" responses (should be ~50% if no bias)
|
||
// YesBias = (Total "Yes" / Total Responses) × 100
|
||
|
||
// Timeout Rate:
|
||
// (Total Timeouts / Total Trials) × 100
|
||
```
|
||
|
||
**Completion Messages (from PDF):**
|
||
|
||
**Adolescents:**
|
||
```
|
||
"Awesome work! You've completed this challenge — stay sharp,
|
||
the next one is coming up!"
|
||
```
|
||
|
||
**Adults:**
|
||
```
|
||
"Well done! You've successfully finished this task —
|
||
let's move on to the next part."
|
||
```
|
||
|
||
**Display Format:**
|
||
|
||
```javascript
|
||
// Results Screen Layout:
|
||
|
||
// 1. COMPLETION MESSAGE (top)
|
||
// Age-appropriate message
|
||
|
||
// 2. OVERALL PERFORMANCE CARD
|
||
// - Total Trials: 650 or 800
|
||
// - Total Correct: XXX
|
||
// - Overall Accuracy: XX.X%
|
||
// - Overall Mean RT: XXXms
|
||
|
||
// 3. PERFORMANCE BY SPAN SIZE (3 cards side-by-side)
|
||
// Adolescents:
|
||
// [1-Letter] [3-Letter] [5-Letter]
|
||
// Adults:
|
||
// [2-Pair] [4-Pair] [6-Pair]
|
||
//
|
||
// Each card shows:
|
||
// - Trials: XX
|
||
// - Correct: XX
|
||
// - Accuracy: XX.X%
|
||
// - Mean RT: XXXms
|
||
|
||
// 4. WORKING MEMORY CAPACITY ESTIMATE
|
||
// - Display highest span with ≥75% accuracy
|
||
// - Simple interpretation message
|
||
// - Example: "Your working memory capacity is approximately 4-5 items"
|
||
|
||
// 5. RT SLOPE ANALYSIS (Optional - Advanced)
|
||
// - Graph or text showing RT increase with memory load
|
||
// - Interpretation: Serial vs. Parallel search strategy
|
||
|
||
// 6. DATA EXPORT SECTION
|
||
// - "Download Results (JSON)" button
|
||
// - "Download Results (CSV)" button
|
||
// - Timestamp and filename generation
|
||
|
||
// 7. NAVIGATION BUTTONS
|
||
// - "Restart Test" (go back to intro)
|
||
// - "Next Assessment" (continue to next test in battery)
|
||
```
|
||
|
||
**Interpretation Guidance:**
|
||
|
||
```javascript
|
||
// Accuracy Interpretation:
|
||
// - ≥85%: Excellent working memory
|
||
// - 70-84%: Good working memory
|
||
// - 60-69%: Average working memory
|
||
// - <60%: May indicate difficulties with working memory
|
||
|
||
// RT Interpretation:
|
||
// - Faster RT with high accuracy: Efficient processing
|
||
// - Slower RT with high accuracy: Careful, accurate processing
|
||
// - Faster RT with low accuracy: Impulsive responding
|
||
// - Slower RT with low accuracy: Processing difficulties
|
||
|
||
// Span Analysis:
|
||
// - Accuracy decreases with larger spans: Normal pattern
|
||
// - RT increases with larger spans: Normal serial search pattern
|
||
// - Flat RT across spans: Possible parallel processing (rare)
|
||
|
||
// Capacity Estimate:
|
||
// Adolescents:
|
||
// - 1-letter capacity: Below average
|
||
// - 3-letter capacity: Average
|
||
// - 5-letter capacity: Above average
|
||
|
||
// Adults:
|
||
// - 2-pair capacity: Below average
|
||
// - 4-pair capacity: Average
|
||
// - 6-pair capacity: Above average
|
||
```
|
||
|
||
---
|
||
|
||
## 📁 File Structure Requirements
|
||
|
||
### Project Organization
|
||
|
||
```
|
||
src/
|
||
├── components/
|
||
│ ├── screens/
|
||
│ │ └── VPSM/
|
||
│ │ ├── IntroScreen.jsx
|
||
│ │ ├── PracticeInstructionsScreen.jsx
|
||
│ │ ├── PracticeScreen.jsx
|
||
│ │ ├── PracticeCompleteScreen.jsx
|
||
│ │ ├── MainTestScreen.jsx
|
||
│ │ ├── ResultsScreen.jsx
|
||
│ │ └── SternbergTask.jsx (main orchestrator)
|
||
│ └── shared/
|
||
│ └── VPSM/
|
||
│ ├── MemorySetDisplay.jsx (sequential item presentation)
|
||
│ ├── ProbeDisplay.jsx (single item display)
|
||
│ ├── ResponseButtons.jsx (Yes/No buttons)
|
||
│ ├── FeedbackDisplay.jsx (practice feedback)
|
||
│ ├── FixationCross.jsx (white + symbol)
|
||
│ ├── TrialCounter.jsx (e.g., "Set 5/15", "Probe 12/50")
|
||
│ └── MetricsCard.jsx (results display)
|
||
├── hooks/
|
||
│ └── vpsm/
|
||
│ ├── usePracticeScreen.js
|
||
│ └── useMainTestScreen.js
|
||
├── utils/
|
||
│ ├── vpsmTimer.js (timing management)
|
||
│ ├── vpsmDataCollection.js (trial data recording)
|
||
│ ├── vpsmCalculations.js (accuracy, RT, capacity analysis)
|
||
│ ├── vpsmDataExport.js (JSON/CSV export)
|
||
│ └── vpsmAnimations.js (minimal Framer Motion)
|
||
├── constants/
|
||
│ ├── vpsmConfig.js (timing, spans, response windows)
|
||
│ ├── vpsmInstructions.js (all text content)
|
||
│ └── vpsmTrialSequences.js (all practice + main trials from PDF)
|
||
└── public/
|
||
└── images/
|
||
└── vpsm/
|
||
└── (optional instruction diagrams)
|
||
```
|
||
|
||
---
|
||
|
||
## 🚫 Important Constraints
|
||
|
||
### NEVER Do This
|
||
|
||
1. ❌ Show all memory set items simultaneously (must be sequential)
|
||
2. ❌ Randomize trial order (must follow PDF sequences exactly)
|
||
3. ❌ Show feedback during main test (except timeout message)
|
||
4. ❌ Allow response before probe appears
|
||
5. ❌ Allow more than 6s/4.5s probe response window
|
||
6. ❌ Skip practice phase
|
||
7. ❌ Accept response after time window expires
|
||
8. ❌ Calculate RT for trials without responses or incorrect responses
|
||
9. ❌ Use localStorage or sessionStorage for critical data
|
||
10. ❌ Create complex distracting animations during encoding/probe phases
|
||
11. ❌ Show running score/accuracy during main test
|
||
12. ❌ Mix probe types from different memory sets
|
||
13. ❌ Present retention interval for less than 1 second
|
||
14. ❌ Include timeout trials in RT mean calculations
|
||
|
||
### ALWAYS Do This
|
||
|
||
1. ✅ Present memory set items sequentially (ONE AT A TIME)
|
||
2. ✅ Follow exact trial sequences from PDF (all practice + main trials)
|
||
3. ✅ Implement precise timing (fixation, encoding, retention, probe)
|
||
4. ✅ Show feedback ONLY during practice phase
|
||
5. ✅ Use light blue border for button selection highlight
|
||
6. ✅ Display "Time is up!" on timeout (1 second)
|
||
7. ✅ Present items in WHITE text on BLACK background
|
||
8. ✅ Keep Yes/No buttons visible at bottom throughout probe display
|
||
9. ✅ Track all metrics silently during main test
|
||
10. ✅ Calculate accuracy across all trials (including timeouts as incorrect)
|
||
11. ✅ Calculate RT ONLY for correct responses
|
||
12. ✅ Use black background throughout entire test
|
||
13. ✅ Implement age-specific response times (6s vs 4.5s)
|
||
14. ✅ Analyze performance by memory span size
|
||
15. ✅ Estimate working memory capacity from accuracy patterns
|
||
16. ✅ Complete all probes for a memory set before moving to next set
|
||
17. ✅ Show memory set once, then test all probes sequentially
|
||
|
||
---
|
||
|
||
## 🔧 Development Workflow
|
||
|
||
### Step-by-Step Process
|
||
|
||
1. **Current Phase:** Developer specifies which screen to create
|
||
2. **AI Creates:** Complete screen with all required files and components
|
||
3. **AI Asks:** "Screen [Name] complete. Proceed to [NextScreen]?"
|
||
4. **Developer:** Approves or requests changes
|
||
5. **Repeat:** Until all 6 screens are complete
|
||
|
||
### Code Quality Standards
|
||
|
||
- Use functional components with hooks
|
||
- Separate concerns (logic, UI, data, timing)
|
||
- Add detailed comments for complex timing logic
|
||
- Follow consistent naming conventions
|
||
- Use Tailwind for ALL styling (core utilities only)
|
||
- Handle edge cases (timeout, rapid clicking, double-tap)
|
||
- Create reusable components (memory display, probe display)
|
||
- Optimize re-renders with useMemo/useCallback
|
||
- Precise timing with useRef for timestamps
|
||
- Clean up all timeouts/intervals on component unmount
|
||
|
||
### State Management Pattern
|
||
|
||
```javascript
|
||
// Main App State (useContext or props)
|
||
const [testState, setTestState] = useState({
|
||
currentScreen: 'intro',
|
||
// 'intro' | 'practiceInstructions' | 'practice' |
|
||
// 'practiceComplete' | 'mainTest' | 'results'
|
||
|
||
ageGroup: null, // 'adolescent' | 'adult'
|
||
phase: 'practice', // 'practice' | 'main'
|
||
|
||
currentMemorySetIndex: 0, // 0-14 (15 memory sets in main task)
|
||
currentProbeIndex: 0, // Index within current memory set's probes
|
||
|
||
practiceData: [], // All practice trial records
|
||
mainTestData: [] // All main test trial records
|
||
});
|
||
|
||
// Per-Screen State (Practice/Main Test)
|
||
const [memorySetState, setMemorySetState] = useState({
|
||
// Memory Set Encoding Phase
|
||
showFixation: false,
|
||
encodingPhase: false,
|
||
currentEncodingItem: null, // Current item being displayed
|
||
encodingItemIndex: 0, // Index in memory set (0 to span-1)
|
||
memorySet: [], // Full memory set (e.g., ['A', 'D', 'F'])
|
||
|
||
// Retention Phase
|
||
retentionPhase: false,
|
||
|
||
// Probe Phase
|
||
probePhase: false,
|
||
currentProbe: null, // { probe, type, correctResponse }
|
||
probeStartTime: null,
|
||
|
||
// Response Phase
|
||
responseGiven: false,
|
||
selectedButton: null, // 'Yes' | 'No' | null
|
||
responseTime: null,
|
||
|
||
// Feedback Phase (practice only)
|
||
showFeedback: false,
|
||
feedbackMessage: null
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 Data Recording Requirements
|
||
|
||
### Trial Data Structure
|
||
|
||
Every probe trial must record:
|
||
|
||
```javascript
|
||
{
|
||
// Trial Identification
|
||
roundNumber: number, // Sequential across entire test (1-670 or 1-825)
|
||
phase: 'practice' | 'main',
|
||
trialNumber: number, // Within phase (1-20/25 practice, 1-650/800 main)
|
||
|
||
// Memory Set Information
|
||
memorySetNumber: number, // 1-15 (main task only)
|
||
triadNumber: number, // 1-5 (main task only)
|
||
memorySet: string[], // e.g., ['A', 'D', 'F'] or ['K7', 'C9']
|
||
memorySetSize: number, // 1/3/5 or 2/4/6 (span size)
|
||
|
||
// Probe Information
|
||
probeNumber: number, // 1-N within current memory set
|
||
probe: string, // e.g., 'D' or 'K7'
|
||
probeType: 'Positive' | 'Negative', // Target or Non-Target
|
||
|
||
// Correct Response
|
||
correctResponse: 'Yes' | 'No',
|
||
|
||
// Participant Response
|
||
participantResponse: 'Yes' | 'No' | 'No Response',
|
||
responseAccuracy: 0 | 1, // 1 = correct, 0 = incorrect/timeout
|
||
reactionTime: number | null, // ms from probe onset (null if timeout)
|
||
|
||
// Timestamps
|
||
timestamp: number, // Trial start time (Date.now())
|
||
probeOnsetTimestamp: number, // Exact probe display time
|
||
responseTimestamp: number | null // Exact button press time (null if timeout)
|
||
}
|
||
```
|
||
|
||
### Data Export Format
|
||
|
||
```javascript
|
||
// Export as both JSON and CSV
|
||
|
||
{
|
||
participantInfo: {
|
||
ageGroup: 'adolescent' | 'adult',
|
||
testDate: string, // ISO format
|
||
testStartTime: string,
|
||
testEndTime: string,
|
||
totalDuration: number // seconds
|
||
},
|
||
|
||
summary: {
|
||
// Overall Counts
|
||
totalProbeTrials: 650 | 800,
|
||
totalRoundsAnswered: number,
|
||
totalRoundsNotAnswered: number,
|
||
correctResponses: number,
|
||
incorrectResponses: number,
|
||
|
||
// Overall Performance
|
||
overallAccuracy: number, // percentage (1 decimal)
|
||
overallMeanRT: number, // milliseconds (rounded)
|
||
|
||
// Performance by Span Size
|
||
spanPerformance: {
|
||
// Adolescents:
|
||
span1: {
|
||
totalTrials: 150, // 5 sets × 30 probes
|
||
correct: number,
|
||
incorrect: number,
|
||
accuracy: number, // percentage
|
||
meanRT: number // ms (only correct trials)
|
||
},
|
||
span3: {
|
||
totalTrials: 250, // 5 sets × 50 probes
|
||
correct: number,
|
||
incorrect: number,
|
||
accuracy: number,
|
||
meanRT: number
|
||
},
|
||
span5: {
|
||
totalTrials: 250, // 5 sets × 50 probes
|
||
correct: number,
|
||
incorrect: number,
|
||
accuracy: number,
|
||
meanRT: number
|
||
}
|
||
|
||
// Adults:
|
||
// span2, span4, span6 (same structure)
|
||
},
|
||
|
||
// Working Memory Analysis
|
||
estimatedCapacity: number, // Highest span with ≥75% accuracy
|
||
rtSlope: number, // ms per item increase
|
||
responseBias: number, // % "Yes" responses (should be ~50%)
|
||
timeoutRate: number // % trials with timeout
|
||
},
|
||
|
||
mainTestData: [/* all 650 or 800 main trial records */],
|
||
practiceData: [/* all 20 or 25 practice trial records */]
|
||
}
|
||
```
|
||
|
||
### CSV Export Columns
|
||
|
||
```javascript
|
||
// CSV Headers (match PDF scoring manual):
|
||
"Round Number",
|
||
"Memory Set Size",
|
||
"Probe Item",
|
||
"Probe Type",
|
||
"Participant Response",
|
||
"Response Accuracy",
|
||
"Reaction Time (ms)"
|
||
|
||
// Example rows:
|
||
// 1, 1, G, Positive, Yes, 1, 1250
|
||
// 2, 1, A, Negative, No, 1, 980
|
||
// 3, 1, G, Positive, Yes, 1, 1100
|
||
```
|
||
|
||
---
|
||
|
||
## 🎭 Animation Specifications
|
||
|
||
### Framer Motion Animations (utils/vpsmAnimations.js)
|
||
|
||
```javascript
|
||
// Minimal animations to maintain task integrity and timing precision
|
||
|
||
export const fadeIn = {
|
||
initial: { opacity: 0 },
|
||
animate: { opacity: 1 },
|
||
transition: { duration: 0.3 }
|
||
};
|
||
|
||
export const fixationFade = {
|
||
initial: { opacity: 0 },
|
||
animate: { opacity: 1 },
|
||
exit: { opacity: 0 },
|
||
transition: { duration: 0.15 }
|
||
};
|
||
|
||
export const feedbackAppear = {
|
||
initial: { opacity: 0, scale: 0.95 },
|
||
animate: { opacity: 1, scale: 1 },
|
||
transition: { duration: 0.2 }
|
||
};
|
||
|
||
export const buttonHighlight = {
|
||
initial: { scale: 1 },
|
||
animate: { scale: 1.02 },
|
||
transition: { duration: 0.1 }
|
||
};
|
||
|
||
// NO animations during memory set encoding or probe display
|
||
// Sharp, instant appearance/disappearance for accurate timing
|
||
// Keep focus on memory task, not visual effects
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 Trial Timing Flow (CRITICAL)
|
||
|
||
### Complete Memory Set + Probe Cycle
|
||
|
||
```javascript
|
||
// FOR EACH MEMORY SET (15 total in main task):
|
||
|
||
// ===== ENCODING PHASE =====
|
||
1. Fixation Cross (300ms)
|
||
- White "+" centered on black screen
|
||
- Prepare attention for memory encoding
|
||
|
||
2. Memory Item Display (Sequential)
|
||
- Display FIRST item: 1.1s (adolescent) or 1.3s (adult)
|
||
- Display SECOND item: 1.1s or 1.3s
|
||
- Display THIRD item: 1.1s or 1.3s
|
||
- ... (continue for all items in memory set)
|
||
- Total encoding time = (span size) × (item duration)
|
||
|
||
Examples:
|
||
- 1-letter (G): 1 × 1.1s = 1.1s total
|
||
- 3-letter (A,F,R): 3 × 1.1s = 3.3s total
|
||
- 5-letter (B,D,H,L,Q): 5 × 1.1s = 5.5s total
|
||
- 2-pair (C9,B3): 2 × 1.3s = 2.6s total
|
||
- 4-pair (H6,J4,M2,R8): 4 × 1.3s = 5.2s total
|
||
- 6-pair (F5,K9,L7,P3,T2,U6): 6 × 1.3s = 7.8s total
|
||
|
||
3. Retention Interval (1000ms)
|
||
- Blank black screen
|
||
- Participant holds memory set in mind
|
||
- No external cues - pure working memory maintenance
|
||
|
||
// ===== PROBE TESTING PHASE (Repeat for ALL probes) =====
|
||
FOR EACH PROBE in current memory set:
|
||
|
||
4. Fixation Cross (300ms)
|
||
- Prepare for next probe
|
||
|
||
5. Probe Display + Response Window
|
||
- Display: Single item (probe) + Yes/No buttons
|
||
- Duration: 6s (adolescent) or 4.5s (adult)
|
||
- Wait for response OR timeout
|
||
|
||
If Response:
|
||
- Record button press ("Yes" or "No")
|
||
- Highlight button with light blue border
|
||
- Calculate RT (response timestamp - probe onset timestamp)
|
||
- Determine accuracy (correct = 1, incorrect = 0)
|
||
|
||
If Timeout:
|
||
- Display "Time is up!" (1 second)
|
||
- Record: participantResponse = "No Response"
|
||
- Record: accuracy = 0, RT = null
|
||
|
||
6. Feedback (PRACTICE ONLY)
|
||
- Correct: "Correct! You remembered it right." (1s)
|
||
- Incorrect: "That's okay—try to remember the set carefully." (1.5s)
|
||
- Timeout: "Please press your choice quickly!" (1s)
|
||
- Main test: SKIP (no feedback except timeout message)
|
||
|
||
7. Inter-trial Interval (300ms)
|
||
- Blank black screen
|
||
- Clear displays, prepare for next probe
|
||
|
||
8. NEXT PROBE
|
||
- Go to step 4 (fixation for next probe)
|
||
- Continue until all probes for this memory set complete
|
||
|
||
// ===== NEXT MEMORY SET =====
|
||
9. After all probes complete:
|
||
- Return to step 1 (fixation for new memory set encoding)
|
||
- Load next memory set from triad sequence
|
||
- Continue until all 15 memory sets complete
|
||
|
||
// Total Time Estimates:
|
||
// Adolescent (650 probes):
|
||
// - Average trial: ~8-10 seconds
|
||
// - Total test: ~90-100 minutes
|
||
|
||
// Adult (800 probes):
|
||
// - Average trial: ~7-9 seconds
|
||
// - Total test: ~90-120 minutes
|
||
```
|
||
|
||
### Timeout Handling
|
||
|
||
```javascript
|
||
// If no response within probe window (6s or 4.5s):
|
||
|
||
1. Cancel probe display
|
||
2. Show "Time is up!" message
|
||
- Full screen, white text, bold, centered
|
||
- Display for 1 second
|
||
3. Record trial as:
|
||
- participantResponse: "No Response"
|
||
- responseAccuracy: 0 (incorrect)
|
||
- reactionTime: null (NOT recorded)
|
||
4. Practice only: Show timeout feedback
|
||
5. Inter-trial interval (300ms)
|
||
6. Proceed to next probe
|
||
|
||
// Important: Do NOT count timeouts in RT calculations
|
||
// Only include trials with actual responses in RT means
|
||
```
|
||
|
||
---
|
||
|
||
## 📋 Scoring Logic (CRITICAL)
|
||
|
||
### Response Classification
|
||
|
||
```javascript
|
||
// CORRECT RESPONSE (score = 1):
|
||
|
||
// Positive Probe + "Yes":
|
||
if (probeType === 'Positive' && participantResponse === 'Yes') {
|
||
responseAccuracy = 1;
|
||
correctResponses++;
|
||
|
||
// Record reaction time
|
||
reactionTime = responseTimestamp - probeOnsetTimestamp;
|
||
|
||
// Add to RT array for span-specific analysis
|
||
rtsBySpan[memorySetSize].push(reactionTime);
|
||
}
|
||
|
||
// Negative Probe + "No":
|
||
if (probeType === 'Negative' && participantResponse === 'No') {
|
||
responseAccuracy = 1;
|
||
correctResponses++;
|
||
|
||
// Record reaction time
|
||
reactionTime = responseTimestamp - probeOnsetTimestamp;
|
||
rtsBySpan[memorySetSize].push(reactionTime);
|
||
}
|
||
|
||
// INCORRECT RESPONSE (score = 0):
|
||
|
||
// Positive Probe + "No" (Miss):
|
||
if (probeType === 'Positive' && participantResponse === 'No') {
|
||
responseAccuracy = 0;
|
||
incorrectResponses++;
|
||
// Do NOT record RT
|
||
}
|
||
|
||
// Negative Probe + "Yes" (False Alarm):
|
||
if (probeType === 'Negative' && participantResponse === 'Yes') {
|
||
responseAccuracy = 0;
|
||
incorrectResponses++;
|
||
// Do NOT record RT
|
||
}
|
||
|
||
// Timeout (No Response):
|
||
if (participantResponse === 'No Response') {
|
||
responseAccuracy = 0;
|
||
incorrectResponses++;
|
||
reactionTime = null;
|
||
// Do NOT record RT
|
||
}
|
||
```
|
||
|
||
### Accuracy Calculations
|
||
|
||
```javascript
|
||
// Overall Accuracy:
|
||
overallAccuracy = (totalCorrect / totalProbeTrials) × 100;
|
||
// Example: (585 / 650) × 100 = 90.0%
|
||
|
||
// Accuracy by Span Size:
|
||
// Adolescents:
|
||
span1Accuracy = (correctSpan1 / totalSpan1Trials) × 100;
|
||
// Example: (142 / 150) × 100 = 94.7%
|
||
|
||
span3Accuracy = (correctSpan3 / totalSpan3Trials) × 100;
|
||
// Example: (218 / 250) × 100 = 87.2%
|
||
|
||
span5Accuracy = (correctSpan5 / totalSpan5Trials) × 100;
|
||
// Example: (192 / 250) × 100 = 76.8%
|
||
|
||
// Adults: Same logic for span2, span4, span6
|
||
|
||
// Expected Pattern:
|
||
// - Accuracy should DECREASE as span size increases
|
||
// - This demonstrates working memory capacity limits
|
||
// - Flat accuracy across spans may indicate guessing or issues
|
||
```
|
||
|
||
### Reaction Time Calculations
|
||
|
||
```javascript
|
||
// CRITICAL: Only include CORRECT responses in RT calculations
|
||
|
||
// Overall Mean RT:
|
||
const correctTrialsWithRT = allTrials.filter(t =>
|
||
t.responseAccuracy === 1 && t.reactionTime !== null
|
||
);
|
||
overallMeanRT = sum(correctTrialsWithRT.map(t => t.reactionTime)) / correctTrialsWithRT.length;
|
||
|
||
// Mean RT by Span Size:
|
||
const span1CorrectRTs = allTrials
|
||
.filter(t => t.memorySetSize === 1 && t.responseAccuracy === 1 && t.reactionTime !== null)
|
||
.map(t => t.reactionTime);
|
||
|
||
span1MeanRT = sum(span1CorrectRTs) / span1CorrectRTs.length;
|
||
|
||
// Repeat for span3, span5 (or span2, span4, span6 for adults)
|
||
|
||
// Example Results:
|
||
// Span 1: Mean RT = 980ms
|
||
// Span 3: Mean RT = 1350ms
|
||
// Span 5: Mean RT = 1680ms
|
||
|
||
// Expected Pattern:
|
||
// - RT should INCREASE as span size increases
|
||
// - Indicates serial exhaustive search through memory
|
||
// - Slope of ~40-60ms per item is typical
|
||
```
|
||
|
||
### Working Memory Capacity Estimation
|
||
|
||
```javascript
|
||
// Determine highest span size with accuracy ≥ 75%
|
||
|
||
function estimateCapacity(spanPerformance) {
|
||
const spans = Object.keys(spanPerformance).sort((a, b) =>
|
||
parseInt(a.replace('span', '')) - parseInt(b.replace('span', ''))
|
||
);
|
||
|
||
let estimatedCapacity = 0;
|
||
|
||
for (const span of spans) {
|
||
const spanSize = parseInt(span.replace('span', ''));
|
||
if (spanPerformance[span].accuracy >= 75) {
|
||
estimatedCapacity = spanSize;
|
||
} else {
|
||
break; // Stop at first span below threshold
|
||
}
|
||
}
|
||
|
||
return estimatedCapacity;
|
||
}
|
||
|
||
// Example:
|
||
// Span 1: 95% accuracy → Capacity ≥ 1
|
||
// Span 3: 87% accuracy → Capacity ≥ 3
|
||
// Span 5: 68% accuracy → Capacity = 3 (stopped before 5)
|
||
// Estimated Capacity: 3-4 items
|
||
|
||
// Interpretation:
|
||
// Adolescents:
|
||
// 1 item: Below average working memory
|
||
// 3 items: Average working memory (typical)
|
||
// 5 items: Above average working memory
|
||
|
||
// Adults:
|
||
// 2 pairs: Below average
|
||
// 4 pairs: Average (typical)
|
||
// 6 pairs: Above average
|
||
```
|
||
|
||
### RT Slope Analysis
|
||
|
||
```javascript
|
||
// Calculate rate of RT increase per memory item
|
||
|
||
function calculateRTSlope(spanPerformance) {
|
||
const spans = Object.keys(spanPerformance).map(s => ({
|
||
size: parseInt(s.replace('span', '')),
|
||
rt: spanPerformance[s].meanRT
|
||
})).filter(s => s.rt !== null);
|
||
|
||
// Simple linear regression or two-point calculation
|
||
// Using smallest and largest spans:
|
||
const smallSpan = spans[0];
|
||
const largeSpan = spans[spans.length - 1];
|
||
|
||
const slope = (largeSpan.rt - smallSpan.rt) / (largeSpan.size - smallSpan.size);
|
||
|
||
return Math.round(slope);
|
||
}
|
||
|
||
// Example:
|
||
// 1-letter: 980ms
|
||
// 5-letter: 1680ms
|
||
// Slope = (1680 - 980) / (5 - 1) = 700 / 4 = 175ms per item
|
||
|
||
// Interpretation:
|
||
// - 30-60ms/item: Fast serial search or parallel processing
|
||
// - 60-100ms/item: Typical serial exhaustive search
|
||
// - >100ms/item: Slower processing, potential difficulties
|
||
```
|
||
|
||
### Response Bias Detection
|
||
|
||
```javascript
|
||
// Check for response bias (should be ~50% "Yes" responses)
|
||
|
||
function calculateResponseBias(trials) {
|
||
const responsesGiven = trials.filter(t => t.participantResponse !== 'No Response');
|
||
const yesResponses = responsesGiven.filter(t => t.participantResponse === 'Yes').length;
|
||
|
||
const yesBias = (yesResponses / responsesGiven.length) × 100;
|
||
|
||
return Math.round(yesBias * 10) / 10; // 1 decimal
|
||
}
|
||
|
||
// Interpretation:
|
||
// - 45-55%: No significant bias (ideal)
|
||
// - >60%: Liberal bias (tendency to say "Yes")
|
||
// - <40%: Conservative bias (tendency to say "No")
|
||
|
||
// Note: Since probe types are balanced ~50/50,
|
||
// healthy performance should show ~50% "Yes" responses
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 Key Constants to Define
|
||
|
||
### vpsmConfig.js
|
||
|
||
```javascript
|
||
export const VPSM_CONFIG = {
|
||
// Test Structure
|
||
PRACTICE_TRIALS_ADOLESCENT: 20,
|
||
PRACTICE_TRIALS_ADULT: 25,
|
||
MAIN_MEMORY_SETS: 15,
|
||
TRIADS: 5,
|
||
|
||
// Span Sizes
|
||
ADOLESCENT_SPANS: [1, 3, 5], // letters
|
||
ADULT_SPANS: [2, 4, 6], // alphanumeric pairs
|
||
|
||
// Probe Counts (per memory set)
|
||
ADOLESCENT_PROBES: {
|
||
span1: 30,
|
||
span3: 50,
|
||
span5: 50
|
||
},
|
||
ADULT_PROBES: {
|
||
span2: 30,
|
||
span4: 65,
|
||
span6: 65
|
||
},
|
||
|
||
// Total Probe Counts
|
||
TOTAL_PROBES_ADOLESCENT: 650, // (5 × 30) + (5 × 50) + (5 × 50)
|
||
TOTAL_PROBES_ADULT: 800, // (5 × 30) + (5 × 65) + (5 × 65)
|
||
|
||
// Timing (milliseconds)
|
||
TIMING: {
|
||
FIXATION_DURATION: 300,
|
||
MEMORY_ITEM_DURATION_ADOLESCENT: 1100,
|
||
MEMORY_ITEM_DURATION_ADULT: 1300,
|
||
RETENTION_INTERVAL: 1000,
|
||
PROBE_RESPONSE_WINDOW_ADOLESCENT: 6000,
|
||
PROBE_RESPONSE_WINDOW_ADULT: 4500,
|
||
FEEDBACK_DURATION_CORRECT: 1000,
|
||
FEEDBACK_DURATION_INCORRECT: 1500,
|
||
TIMEOUT_MESSAGE_DURATION: 1000,
|
||
INTER_TRIAL_INTERVAL: 300
|
||
},
|
||
|
||
// UI Constants
|
||
BUTTON_HIGHLIGHT_COLOR: 'ring-blue-400',
|
||
BACKGROUND_COLOR: 'black',
|
||
TEXT_COLOR: 'white',
|
||
STIMULUS_FONT_SIZE: 'text-5xl',
|
||
BUTTONS: ['Yes', 'No'],
|
||
|
||
// Probe Types
|
||
PROBE_TYPES: {
|
||
POSITIVE: 'Positive', // Target - was in memory set
|
||
NEGATIVE: 'Negative' // Non-Target - was NOT in memory set
|
||
},
|
||
|
||
// Capacity Estimation
|
||
CAPACITY_THRESHOLD: 75, // % accuracy threshold for capacity estimate
|
||
|
||
// Response Bias Thresholds
|
||
BIAS_THRESHOLDS: {
|
||
LIBERAL_CUTOFF: 60, // >60% "Yes" = liberal bias
|
||
CONSERVATIVE_CUTOFF: 40 // <40% "Yes" = conservative bias
|
||
}
|
||
};
|
||
```
|
||
|
||
### vpsmCalculations.js
|
||
|
||
```javascript
|
||
// Purpose: Calculate all performance metrics from trial data
|
||
|
||
export const calculateVpsmMetrics = (trialData, ageGroup) => {
|
||
// Filter main test trials only (exclude practice)
|
||
const mainTrials = trialData.filter(t => t.phase === 'main');
|
||
|
||
// Determine spans based on age group
|
||
const spans = ageGroup === 'adolescent'
|
||
? [1, 3, 5]
|
||
: [2, 4, 6];
|
||
|
||
// Count responses
|
||
const totalRoundsAnswered = mainTrials.filter(
|
||
t => t.participantResponse !== 'No Response'
|
||
).length;
|
||
|
||
const totalRoundsNotAnswered = mainTrials.filter(
|
||
t => t.participantResponse === 'No Response'
|
||
).length;
|
||
|
||
// Count correct/incorrect
|
||
const correctResponses = mainTrials.filter(
|
||
t => t.responseAccuracy === 1
|
||
).length;
|
||
|
||
const incorrectResponses = mainTrials.filter(
|
||
t => t.responseAccuracy === 0
|
||
).length;
|
||
|
||
// Calculate overall accuracy
|
||
const overallAccuracy = (correctResponses / mainTrials.length) * 100;
|
||
|
||
// Calculate overall mean RT (correct responses only)
|
||
const correctRTs = mainTrials
|
||
.filter(t => t.responseAccuracy === 1 && t.reactionTime !== null)
|
||
.map(t => t.reactionTime);
|
||
|
||
const overallMeanRT = correctRTs.length > 0
|
||
? correctRTs.reduce((sum, rt) => sum + rt, 0) / correctRTs.length
|
||
: null;
|
||
|
||
// Calculate performance by span size
|
||
const spanPerformance = {};
|
||
|
||
spans.forEach(span => {
|
||
const spanTrials = mainTrials.filter(t => t.memorySetSize === span);
|
||
const spanCorrect = spanTrials.filter(t => t.responseAccuracy === 1);
|
||
const spanRTs = spanCorrect
|
||
.filter(t => t.reactionTime !== null)
|
||
.map(t => t.reactionTime);
|
||
|
||
spanPerformance[`span${span}`] = {
|
||
totalTrials: spanTrials.length,
|
||
correct: spanCorrect.length,
|
||
incorrect: spanTrials.length - spanCorrect.length,
|
||
accuracy: (spanCorrect.length / spanTrials.length) * 100,
|
||
meanRT: spanRTs.length > 0
|
||
? spanRTs.reduce((sum, rt) => sum + rt, 0) / spanRTs.length
|
||
: null
|
||
};
|
||
});
|
||
|
||
// Estimate working memory capacity
|
||
let estimatedCapacity = 0;
|
||
for (const span of spans) {
|
||
if (spanPerformance[`span${span}`].accuracy >= 75) {
|
||
estimatedCapacity = span;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Calculate RT slope
|
||
const spanWithRTs = spans
|
||
.map(span => ({
|
||
size: span,
|
||
rt: spanPerformance[`span${span}`].meanRT
|
||
}))
|
||
.filter(s => s.rt !== null);
|
||
|
||
let rtSlope = null;
|
||
if (spanWithRTs.length >= 2) {
|
||
const smallest = spanWithRTs[0];
|
||
const largest = spanWithRTs[spanWithRTs.length - 1];
|
||
rtSlope = (largest.rt - smallest.rt) / (largest.size - smallest.size);
|
||
}
|
||
|
||
// Calculate response bias
|
||
const responsesGiven = mainTrials.filter(
|
||
t => t.participantResponse !== 'No Response'
|
||
);
|
||
const yesResponses = responsesGiven.filter(
|
||
t => t.participantResponse === 'Yes'
|
||
).length;
|
||
const responseBias = (yesResponses / responsesGiven.length) * 100;
|
||
|
||
// Calculate timeout rate
|
||
const timeoutRate = (totalRoundsNotAnswered / mainTrials.length) * 100;
|
||
|
||
return {
|
||
// Overall Counts
|
||
totalProbeTrials: mainTrials.length,
|
||
totalRoundsAnswered,
|
||
totalRoundsNotAnswered,
|
||
correctResponses,
|
||
incorrectResponses,
|
||
|
||
// Overall Performance
|
||
overallAccuracy: Math.round(overallAccuracy * 10) / 10,
|
||
overallMeanRT: overallMeanRT ? Math.round(overallMeanRT) : null,
|
||
|
||
// Span-Specific Performance
|
||
spanPerformance: Object.fromEntries(
|
||
Object.entries(spanPerformance).map(([key, value]) => [
|
||
key,
|
||
{
|
||
...value,
|
||
accuracy: Math.round(value.accuracy * 10) / 10,
|
||
meanRT: value.meanRT ? Math.round(value.meanRT) : null
|
||
}
|
||
])
|
||
),
|
||
|
||
// Working Memory Analysis
|
||
estimatedCapacity,
|
||
rtSlope: rtSlope ? Math.round(rtSlope) : null,
|
||
responseBias: Math.round(responseBias * 10) / 10,
|
||
timeoutRate: Math.round(timeoutRate * 10) / 10
|
||
};
|
||
};
|
||
|
||
// Interpretation helpers
|
||
export const interpretCapacity = (capacity, ageGroup) => {
|
||
if (ageGroup === 'adolescent') {
|
||
if (capacity >= 5) return 'Above average working memory capacity';
|
||
if (capacity >= 3) return 'Average working memory capacity';
|
||
if (capacity >= 1) return 'Below average working memory capacity';
|
||
return 'Difficulty with working memory tasks';
|
||
} else {
|
||
if (capacity >= 6) return 'Above average working memory capacity';
|
||
if (capacity >= 4) return 'Average working memory capacity';
|
||
if (capacity >= 2) return 'Below average working memory capacity';
|
||
return 'Difficulty with working memory tasks';
|
||
}
|
||
};
|
||
|
||
export const interpretRTSlope = (slope) => {
|
||
if (slope === null) return 'Insufficient data';
|
||
if (slope < 60) return 'Fast serial search or possible parallel processing';
|
||
if (slope < 100) return 'Typical serial exhaustive search pattern';
|
||
return 'Slower processing - may indicate working memory difficulties';
|
||
};
|
||
|
||
export const interpretResponseBias = (bias) => {
|
||
if (bias > 60) return 'Liberal response bias (tendency to respond "Yes")';
|
||
if (bias < 40) return 'Conservative response bias (tendency to respond "No")';
|
||
return 'No significant response bias detected';
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 Development Notes
|
||
|
||
### Critical Reminders
|
||
|
||
1. **Follow PDF exactly** - All practice + main trials must match document precisely
|
||
2. **Sequential presentation** - Memory items shown ONE AT A TIME (never all at once)
|
||
3. **Timing precision** - Use performance.now() for accurate RT measurement
|
||
4. **RT calculation** - Only include correct responses in mean RT calculations
|
||
5. **Capacity analysis** - This is a primary outcome measure - ensure accuracy
|
||
6. **No feedback in main test** - Only show timeout message, no correct/incorrect feedback
|
||
7. **Complete all probes** - Test all probes for a memory set before moving to next set
|
||
8. **Span progression** - Alternating 1→3→5 or 2→4→6 pattern across 5 triads
|
||
9. **Age-appropriate** - Different stimuli, timings, and language for each age group
|
||
|
||
### Common Pitfalls to Avoid
|
||
|
||
- ❌ Showing all memory items simultaneously (must be sequential)
|
||
- ❌ Including incorrect responses in RT means
|
||
- ❌ Including timeout trials in RT calculations
|
||
- ❌ Showing feedback during main test (except timeout)
|
||
- ❌ Randomizing trial order (must follow PDF exactly)
|
||
- ❌ Using wrong item display time (1.1s vs 1.3s)
|
||
- ❌ Using wrong probe window (6s vs 4.5s)
|
||
- ❌ Forgetting retention interval (1 second blank screen)
|
||
- ❌ Not clearing timeouts on component unmount
|
||
- ❌ Not handling rapid/duplicate button presses
|
||
- ❌ Calculating accuracy without including timeouts as incorrect
|
||
- ❌ Testing probes before showing full memory set
|
||
|
||
### Performance Optimization
|
||
|
||
- Use useCallback for event handlers to prevent re-renders
|
||
- Use useRef for timers and timestamps (no re-renders needed)
|
||
- Use useMemo for trial sequences and span calculations
|
||
- Debounce button clicks to prevent double-taps
|
||
- Clean up all timeouts/intervals on unmount
|
||
- Lazy load results calculations until test completion
|
||
- Minimize state updates during encoding/probe phases
|
||
- Pre-calculate trial sequences to avoid runtime computation
|
||
|
||
### Accessibility Considerations
|
||
|
||
- High contrast text (white on black)
|
||
- Large, readable font sizes (text-5xl minimum)
|
||
- Clear button labels ("Yes" and "No")
|
||
- Keyboard support (Y key = Yes, N key = No)
|
||
- Screen reader announcements for phase transitions
|
||
- Focus management between screens
|
||
- Touch-friendly button sizes (minimum 44x44px)
|
||
- Clear visual feedback on button press (light blue border)
|
||
|
||
---
|
||
|
||
## 🎓 Learning Resources
|
||
|
||
### Key Concepts to Understand
|
||
|
||
1. **Working Memory:** Temporary storage and manipulation of information
|
||
2. **Memory Span:** Maximum number of items that can be held in working memory
|
||
3. **Serial Exhaustive Search:** Mental process of checking each item sequentially
|
||
4. **Recognition vs. Recall:** Identifying previously seen items (easier than recall)
|
||
5. **Cognitive Load:** Difficulty increases with larger memory sets
|
||
6. **Positive vs. Negative Probes:** Targets (in set) vs. Non-Targets (not in set)
|
||
7. **RT Slope:** Rate of RT increase with memory load (search efficiency)
|
||
8. **Capacity Limits:** Individual differences in working memory capacity
|
||
|
||
### React Patterns Used
|
||
|
||
- Custom hooks for complex state logic (useMemorySetManagement)
|
||
- useRef for timers and timestamps (performance optimization)
|
||
- useCallback for optimized event handlers
|
||
- useMemo for trial sequence calculations
|
||
- Framer Motion for minimal animations
|
||
- Context API for global test state (optional)
|
||
- Compound components pattern
|
||
- Sequential state machines for trial flow
|
||
|
||
---
|
||
|
||
**FINAL REMINDER:**
|
||
|
||
This is a psychological research tool measuring working memory capacity. Precision in:
|
||
- **Sequential presentation** of memory items (ONE AT A TIME)
|
||
- **Timing accuracy** (encoding, retention, probe windows)
|
||
- **Data collection** (every probe trial recorded accurately)
|
||
- **RT measurement** (millisecond precision)
|
||
- **Calculations** (only correct responses in RT means)
|
||
|
||
is ABSOLUTELY CRITICAL for valid assessment.
|
||
|
||
Always refer back to the PDF for exact specifications. When in doubt, follow the PDF exactly.
|
||
|
||
The Sternberg paradigm is a validated scientific instrument - maintain its integrity through precise implementation.
|