CP_AUTOMATION/CognitivePrism/my-project/cognitive-docs/Doc/vpam_rules.md
2025-12-12 19:54:54 +05:30

2471 lines
73 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This project implements a **Visual Paired Associates Memory (VPAM) Test** frontend application for psychological research. The test measures associative memory, encoding, retention, consolidation, and recognition abilities by teaching participants picture-picture pairs and testing recall at multiple time points.
## Response Requirements
**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)
- **Total Pairs:** 35 unique picture-picture pairs
- **Encoding Phase:** Learn all 35 pairs (one-time exposure)
- **Immediate Cued Recall:** Test immediately after encoding (35 trials)
- **Delay Interval:** 15 minutes with filler tasks
- **Delayed Cued Recall:** Test after delay (35 trials)
- **Recognition Phase:** Multiple choice recognition (35 trials)
- **Total Time:** Approximately 30-35 minutes
### Age Groups
1. **Adolescents (14-18 years):**
- Exposure time: 3.5 seconds per pair
- Recall response time: 15 seconds per trial
- Recognition response time: 4 seconds per trial
- Colorful gradient background
- Friendly, encouraging instructions
- Pairs: Pen+Kite, Butterfly+Spoon, Elephant+Mango, etc. (35 pairs)
2. **Adults (18-22 years):**
- Exposure time: 2.5 seconds per pair
- Recall response time: 15 seconds per trial
- Recognition response time: 4 seconds per trial
- Soft neutral background
- Professional, concise instructions
- Pairs: Mixer+Spectacles, Mobile Phone+Water Tap, Lemon+Socks, etc. (35 pairs)
---
## 🔑 Critical Implementation Rules
### Phase 1: Encoding (Learning Phase)
```javascript
// ENCODING RULES:
// 1. Display 35 pairs sequentially
// 2. Each pair shown for 3.5s (adolescents) or 2.5s (adults)
// 3. NO response required - passive viewing only
// 4. Pairs displayed in WHITE BOX, centered on screen
// 5. Automatic progression to next pair
// 6. After last pair → immediately transition to Immediate Recall
// Pair Display Format:
// [Image 1] + [Image 2]
// Side by side or stacked (specify in design)
```
**Adolescent Pairs (EXACT ORDER from PDF):**
```javascript
[
{ first: 'Pen', second: 'Kite' },
{ first: 'Butterfly', second: 'Spoon' },
{ first: 'Elephant', second: 'Mango' },
{ first: 'Lock', second: 'Flute' },
{ first: 'Notebook', second: 'Cow' },
{ first: 'Eraser', second: 'Cup' },
{ first: 'Tomato', second: 'Bag' },
{ first: 'Heart', second: 'Scissors' },
{ first: 'Drum', second: 'Goat' },
{ first: 'Phone', second: 'Auto' },
{ first: 'Table', second: 'Parrot' },
{ first: 'Robot', second: 'Chair' },
{ first: 'Ship', second: 'Potato' },
{ first: 'Pencil', second: 'Dice' },
{ first: 'Belt', second: 'Lemon' },
{ first: 'Hibiscus', second: 'Bike' },
{ first: 'Carrot', second: 'Peacock' },
{ first: 'Candle', second: 'Balloon' },
{ first: 'Fork', second: 'Bulb' },
{ first: 'Sharpener', second: 'Lotus' },
{ first: 'Shirt', second: 'Banana' },
{ first: 'Chain', second: 'Jug' },
{ first: 'Hand', second: 'Rat' },
{ first: 'Television', second: 'Coconut' },
{ first: 'Book', second: 'Key' },
{ first: 'Shoe', second: 'Ears' },
{ first: 'Dog', second: 'Crown' },
{ first: 'Cloud', second: 'Mirror' },
{ first: 'Cycle', second: 'Plate' },
{ first: 'Pig', second: 'Clock' },
{ first: 'Watch', second: 'Crayon' },
{ first: 'Leaf', second: 'Pant' },
{ first: 'Door', second: 'Apple' },
{ first: 'Hat', second: 'Ring' },
{ first: 'Bucket', second: 'Monkey' }
]
```
**Adult Pairs (EXACT ORDER from PDF):**
```javascript
[
{ first: 'Mixer', second: 'Spectacles' },
{ first: 'Mobile Phone', second: 'Water Tap' },
{ first: 'Lemon', second: 'Socks' },
{ first: 'Plane', second: 'Lamp' },
{ first: 'Pillow', second: 'Mug' },
{ first: 'Bowl', second: 'Switch' },
{ first: 'Helmet', second: 'Rose' },
{ first: 'Shark', second: 'Fan' },
{ first: 'Sun', second: 'Table' },
{ first: 'Rock', second: 'Peas' },
{ first: 'Chilli', second: 'Hen' },
{ first: 'Window', second: 'Orange' },
{ first: 'Purse', second: 'Hammer' },
{ first: 'Zebra', second: 'Almonds' },
{ first: 'Ball', second: 'Nose' },
{ first: 'Rope', second: 'Ice Cream' },
{ first: 'Horse', second: 'Umbrella' },
{ first: 'Nose', second: 'Cauliflower' },
{ first: 'Pen', second: 'Chair' },
{ first: 'Clock', second: 'Dustbin' },
{ first: 'Laptop', second: 'Moon' },
{ first: 'Crocodile', second: 'Brush' },
{ first: 'Cup', second: 'Rainbow' },
{ first: 'Scooter', second: 'Calendar' },
{ first: 'Camel', second: 'Key' },
{ first: 'Bank', second: 'Watermelon' },
{ first: 'Jug', second: 'Beetle' },
{ first: 'Iron Box', second: 'Strawberry' },
{ first: 'Sunflower', second: 'Ladder' },
{ first: 'Screwdriver', second: 'Garlic' },
{ first: 'Basket', second: 'Train' },
{ first: 'Camera', second: 'Starfish' },
{ first: 'Lady\'s Finger', second: 'Candle' },
{ first: 'Torch Light', second: 'Mat' },
{ first: 'Cherry', second: 'Mirror' }
]
```
---
### Phase 2: Immediate Cued Recall
```javascript
// IMMEDIATE RECALL RULES:
// 1. Show ONE item from each learned pair as CUE
// 2. Participant types the MATCHING item
// 3. 15 seconds response window per trial
// 4. Text input field below cue image
// 5. Automatic advance on submit OR timeout
// 6. Show "Time is up!" for 1 second on timeout
// 7. NO feedback on correctness during test
// 8. Order: Show SECOND item, ask for FIRST (or vice versa)
// Response Validation:
// - Must match EXACT item name (case-insensitive)
// - Don't accept categories ("animal" vs "Elephant")
// - Don't accept descriptors ("red apple" vs "Apple")
// - Trim whitespace, ignore punctuation
```
**Adolescent Immediate Recall Cues (EXACT ORDER):**
```javascript
[
{ cue: 'Kite', correctAnswer: 'Pen' },
{ cue: 'Butterfly', correctAnswer: 'Spoon' },
{ cue: 'Mango', correctAnswer: 'Elephant' },
{ cue: 'Flute', correctAnswer: 'Lock' },
{ cue: 'Notebook', correctAnswer: 'Cow' },
{ cue: 'Eraser', correctAnswer: 'Cup' },
{ cue: 'Bag', correctAnswer: 'Tomato' },
{ cue: 'Heart', correctAnswer: 'Scissors' },
{ cue: 'Drum', correctAnswer: 'Goat' },
{ cue: 'Auto', correctAnswer: 'Phone' },
{ cue: 'Parrot', correctAnswer: 'Table' },
{ cue: 'Robot', correctAnswer: 'Chair' },
{ cue: 'Potato', correctAnswer: 'Ship' },
{ cue: 'Dice', correctAnswer: 'Pencil' },
{ cue: 'Belt', correctAnswer: 'Lemon' },
{ cue: 'Bike', correctAnswer: 'Hibiscus' },
{ cue: 'Peacock', correctAnswer: 'Carrot' },
{ cue: 'Balloon', correctAnswer: 'Candle' },
{ cue: 'Bulb', correctAnswer: 'Fork' },
{ cue: 'Sharpener', correctAnswer: 'Lotus' },
{ cue: 'Banana', correctAnswer: 'Shirt' },
{ cue: 'Jug', correctAnswer: 'Chain' },
{ cue: 'Rat', correctAnswer: 'Hand' },
{ cue: 'Coconut', correctAnswer: 'Television' },
{ cue: 'Key', correctAnswer: 'Book' },
{ cue: 'Ears', correctAnswer: 'Shoe' },
{ cue: 'Dog', correctAnswer: 'Crown' },
{ cue: 'Mirror', correctAnswer: 'Cloud' },
{ cue: 'Plate', correctAnswer: 'Cycle' },
{ cue: 'Clock', correctAnswer: 'Pig' },
{ cue: 'Crayon', correctAnswer: 'Watch' },
{ cue: 'Pant', correctAnswer: 'Leaf' },
{ cue: 'Apple', correctAnswer: 'Door' },
{ cue: 'Ring', correctAnswer: 'Hat' },
{ cue: 'Monkey', correctAnswer: 'Bucket' }
]
```
**Adult Immediate Recall Cues (EXACT ORDER):**
```javascript
[
{ cue: 'Spectacles', correctAnswer: 'Mixer' },
{ cue: 'Water Tap', correctAnswer: 'Mobile Phone' },
{ cue: 'Lemon', correctAnswer: 'Socks' },
{ cue: 'Plane', correctAnswer: 'Lamp' },
{ cue: 'Mug', correctAnswer: 'Pillow' },
{ cue: 'Switch', correctAnswer: 'Bowl' },
{ cue: 'Rose', correctAnswer: 'Helmet' },
{ cue: 'Shark', correctAnswer: 'Fan' },
{ cue: 'Table', correctAnswer: 'Sun' },
{ cue: 'Peas', correctAnswer: 'Rock' },
{ cue: 'Hen', correctAnswer: 'Chilli' },
{ cue: 'Orange', correctAnswer: 'Window' },
{ cue: 'Purse', correctAnswer: 'Hammer' },
{ cue: 'Zebra', correctAnswer: 'Almonds' },
{ cue: 'Nose', correctAnswer: 'Ball' },
{ cue: 'Ice Cream', correctAnswer: 'Rope' },
{ cue: 'Umbrella', correctAnswer: 'Horse' },
{ cue: 'Cauliflower', correctAnswer: 'Nose' },
{ cue: 'Chair', correctAnswer: 'Pen' },
{ cue: 'Dustbin', correctAnswer: 'Clock' },
{ cue: 'Moon', correctAnswer: 'Laptop' },
{ cue: 'Brush', correctAnswer: 'Crocodile' },
{ cue: 'Rainbow', correctAnswer: 'Cup' },
{ cue: 'Calendar', correctAnswer: 'Scooter' },
{ cue: 'Camel', correctAnswer: 'Key' },
{ cue: 'Watermelon', correctAnswer: 'Bank' },
{ cue: 'Beetle', correctAnswer: 'Jug' },
{ cue: 'Strawberry', correctAnswer: 'Iron Box' },
{ cue: 'Ladder', correctAnswer: 'Sunflower' },
{ cue: 'Garlic', correctAnswer: 'Screwdriver' },
{ cue: 'Train', correctAnswer: 'Basket' },
{ cue: 'Starfish', correctAnswer: 'Camera' },
{ cue: 'Candle', correctAnswer: 'Lady\'s Finger' },
{ cue: 'Mat', correctAnswer: 'Torch Light' },
{ cue: 'Mirror', correctAnswer: 'Cherry' }
]
```
---
### Phase 3: Delay Interval (15 Minutes)
```javascript
// DELAY INTERVAL RULES:
// 1. Duration: EXACTLY 15 minutes
// 2. Filler tasks administered sequentially:
// a. Response Inhibition Task (Go/No-Go)
// b. Cognitive Flexibility Task
// c. Stroop Task (Attention)
// 3. These tasks prevent rehearsal of learned pairs
// 4. After 15 minutes → automatically launch Delayed Recall
// 5. Do NOT allow participant to skip or pause
// Transition Message:
// Adolescents: "Great job looking at all the pairs! Before we test
// your memory, you'll play a few short brain-teaser games..."
// Adults: "Well done—you've completed the first part. Next, you'll do
// a few short thinking activities designed to keep your mind active..."
```
**Filler Task Integration:**
- Import existing RIT component
- Import existing CFT component
- Import existing Stroop component (to be developed)
- Chain them sequentially
- Track total elapsed time
- Trigger Delayed Recall at exactly 15:00 minutes
---
### Phase 4: Delayed Cued Recall
```javascript
// DELAYED RECALL RULES:
// 1. Identical to Immediate Recall in format
// 2. Show OPPOSITE cue from immediate recall
// - If immediate showed SECOND → now show FIRST
// - If immediate showed FIRST → now show SECOND
// 3. Same 15-second response window
// 4. Same text input validation
// 5. "Time is up!" message on timeout
// 6. NO feedback on correctness
// Purpose: Measure retention and forgetting over time
// Compare performance: Delayed vs Immediate
```
**Adolescent Delayed Recall Cues (EXACT ORDER):**
```javascript
[
{ cue: 'Pen', correctAnswer: 'Kite' },
{ cue: 'Spoon', correctAnswer: 'Butterfly' },
{ cue: 'Elephant', correctAnswer: 'Mango' },
{ cue: 'Lock', correctAnswer: 'Flute' },
{ cue: 'Cow', correctAnswer: 'Notebook' },
{ cue: 'Cup', correctAnswer: 'Eraser' },
{ cue: 'Tomato', correctAnswer: 'Bag' },
{ cue: 'Scissors', correctAnswer: 'Heart' },
{ cue: 'Goat', correctAnswer: 'Drum' },
{ cue: 'Phone', correctAnswer: 'Auto' },
{ cue: 'Table', correctAnswer: 'Parrot' },
{ cue: 'Chair', correctAnswer: 'Robot' },
{ cue: 'Ship', correctAnswer: 'Potato' },
{ cue: 'Pencil', correctAnswer: 'Dice' },
{ cue: 'Lemon', correctAnswer: 'Belt' },
{ cue: 'Hibiscus', correctAnswer: 'Bike' },
{ cue: 'Carrot', correctAnswer: 'Peacock' },
{ cue: 'Candle', correctAnswer: 'Balloon' },
{ cue: 'Fork', correctAnswer: 'Bulb' },
{ cue: 'Lotus', correctAnswer: 'Sharpener' },
{ cue: 'Shirt', correctAnswer: 'Banana' },
{ cue: 'Chain', correctAnswer: 'Jug' },
{ cue: 'Hand', correctAnswer: 'Rat' },
{ cue: 'Television', correctAnswer: 'Coconut' },
{ cue: 'Book', correctAnswer: 'Key' },
{ cue: 'Shoe', correctAnswer: 'Ears' },
{ cue: 'Crown', correctAnswer: 'Dog' },
{ cue: 'Cloud', correctAnswer: 'Mirror' },
{ cue: 'Cycle', correctAnswer: 'Plate' },
{ cue: 'Pig', correctAnswer: 'Clock' },
{ cue: 'Watch', correctAnswer: 'Crayon' },
{ cue: 'Leaf', correctAnswer: 'Pant' },
{ cue: 'Door', correctAnswer: 'Apple' },
{ cue: 'Hat', correctAnswer: 'Ring' },
{ cue: 'Bucket', correctAnswer: 'Monkey' }
]
```
**Adult Delayed Recall Cues (EXACT ORDER):**
```javascript
[
{ cue: 'Mixer', correctAnswer: 'Spectacles' },
{ cue: 'Mobile Phone', correctAnswer: 'Water Tap' },
{ cue: 'Socks', correctAnswer: 'Lemon' },
{ cue: 'Lamp', correctAnswer: 'Plane' },
{ cue: 'Pillow', correctAnswer: 'Mug' },
{ cue: 'Bowl', correctAnswer: 'Switch' },
{ cue: 'Helmet', correctAnswer: 'Rose' },
{ cue: 'Fan', correctAnswer: 'Shark' },
{ cue: 'Sun', correctAnswer: 'Table' },
{ cue: 'Rock', correctAnswer: 'Peas' },
{ cue: 'Chilli', correctAnswer: 'Hen' },
{ cue: 'Window', correctAnswer: 'Orange' },
{ cue: 'Hammer', correctAnswer: 'Purse' },
{ cue: 'Almonds', correctAnswer: 'Zebra' },
{ cue: 'Ball', correctAnswer: 'Nose' },
{ cue: 'Rope', correctAnswer: 'Ice Cream' },
{ cue: 'Horse', correctAnswer: 'Umbrella' },
{ cue: 'Nose', correctAnswer: 'Cauliflower' },
{ cue: 'Pen', correctAnswer: 'Chair' },
{ cue: 'Clock', correctAnswer: 'Dustbin' },
{ cue: 'Laptop', correctAnswer: 'Moon' },
{ cue: 'Crocodile', correctAnswer: 'Brush' },
{ cue: 'Cup', correctAnswer: 'Rainbow' },
{ cue: 'Scooter', correctAnswer: 'Calendar' },
{ cue: 'Key', correctAnswer: 'Camel' },
{ cue: 'Bank', correctAnswer: 'Watermelon' },
{ cue: 'Jug', correctAnswer: 'Beetle' },
{ cue: 'Iron Box', correctAnswer: 'Strawberry' },
{ cue: 'Sunflower', correctAnswer: 'Ladder' },
{ cue: 'Screwdriver', correctAnswer: 'Garlic' },
{ cue: 'Basket', correctAnswer: 'Train' },
{ cue: 'Camera', correctAnswer: 'Starfish' },
{ cue: 'Candle', correctAnswer: 'Lady\'s Finger' },
{ cue: 'Torch Light', correctAnswer: 'Mat' },
{ cue: 'Cherry', correctAnswer: 'Mirror' }
]
```
---
### Phase 5: Recognition Phase
```javascript
// RECOGNITION RULES:
// 1. Show cue image at top in white box
// 2. Display THREE options horizontally below:
// a. Correct target (the actual paired item)
// b. Related distractor (same category as target)
// c. Unrelated distractor (different category)
// 3. RANDOMIZE option positions each trial
// 4. 4-second response window (FAST!)
// 5. Click/tap to select
// 6. Immediate advance on selection
// 7. "Too Late" message for 1 second on timeout
// 8. NO feedback on correctness
// Distractor Selection Logic:
// - Related: Same semantic category (animal→animal, food→food)
// - Unrelated: Completely different category
// - Balance distractor difficulty across trials
```
**Adolescent Recognition Trials (EXACT ORDER with distractors):**
```javascript
[
{
cue: 'Pen',
correctTarget: 'Kite',
relatedDistractor: 'Parachute',
unrelatedDistractor: 'Elephant'
},
{
cue: 'Butterfly',
correctTarget: 'Spoon',
relatedDistractor: 'Knife',
unrelatedDistractor: 'Scooter'
},
{
cue: 'Mango',
correctTarget: 'Elephant',
relatedDistractor: 'Cow',
unrelatedDistractor: 'Phone'
},
// ... (all 35 trials with distractors from PDF)
]
```
**Adult Recognition Trials (EXACT ORDER with distractors):**
```javascript
[
{
cue: 'Mixer',
correctTarget: 'Spectacles',
relatedDistractor: 'Sunglasses',
unrelatedDistractor: 'Apple'
},
{
cue: 'Mobile Phone',
correctTarget: 'Water Tap',
relatedDistractor: 'Shower',
unrelatedDistractor: 'Cow'
},
{
cue: 'Lemon',
correctTarget: 'Socks',
relatedDistractor: 'Shoe',
unrelatedDistractor: 'Mango'
},
// ... (all 35 trials with distractors from PDF)
]
```
---
## 📱 Screen Flow (Sequential Development)
### Development Order (ONE SCREEN AT A TIME)
#### Screen 1: IntroScreen
**Purpose:** Welcome participants and select age group
**Components needed:**
- Welcome header with test title
- Test overview description
- Age group selector (14-18 vs 18-22)
- "Let's Go!" button to start
**Required files:**
- `components/screens/VPAM/DelayedRecallInstructionScreen.jsx`
**Instructions:**
Adolescents:
```
"Welcome back to the memory game you played earlier! Remember, you saw
pairs of items and tried to learn which ones go together. Now, again, one
item from each pair will appear alone. Your task is to write the item that
goes with it. You'll have a short time for each one, so try to answer quickly.
If you don't respond in time, the game will say 'Time is up!' and move on
to the next item.
Write the exact item that goes with the one you see. Don't just write a
general category, color, or size of the object — try to remember the
specific pair.
Example: If you see 🍎 Apple and it was paired with 🪑 Chair, write 'Chair',
not 'furniture' or 'brown chair' or 'big chair'."
```
Adults:
```
"We're returning to the memory task you did before. Earlier, you learned
pairs of items and tried to remember which ones belonged together. In this
part, again, a single item from each pair will appear alone. Your task is
to type or write the item that was originally paired with it. You will have
limited time to respond for each item. If you do not answer within the time
limit, the message 'Time is up!' will appear and the task will move on.
Type the exact item that was paired with the cue you see. Do not write a
general category, color, or size of the object — focus on the specific
paired item.
Example: If the cue is 🖊️ Pen and it was paired with 🐘 Elephant, type
'Elephant', not 'animal', 'creature', or 'grey elephant' or 'big elephant'."
```
---
#### Screen 8: DelayedRecallScreen
**Purpose:** Test memory retention after 15-minute delay
**Components needed:**
- Same as ImmediateRecallScreen
- Reuse RecallInput component
- Different cue sequence
**Required files:**
- `components/screens/VPAM/DelayedRecallScreen.jsx`
- Reuse: `components/shared/VPAM/RecallInput.jsx`
- Extend: `hooks/vpam/useRecallScreen.js`
**Logic:**
- Identical to Immediate Recall
- Use OPPOSITE cue from immediate recall
- Same 15-second response window
- Same validation rules
- Track all same metrics
- After trial 35 → transition to Recognition
---
#### Screen 9: RecognitionInstructionScreen
**Purpose:** Explain multiple choice recognition task
**Components needed:**
- Instruction text
- Visual example of 3-option layout
- Speed reminder (4 seconds!)
- "Let's Go!" button
**Required files:**
- `components/screens/VPAM/RecognitionInstructionScreen.jsx`
**Instructions:**
Adolescents:
```
"Next, you'll see one picture at the top of the screen. Below it, you'll
see three choices. Your job is to pick the picture that was originally
paired with the one on top. Be quick—you'll only have a few seconds for
each choice. If you don't tap the suitable choice on time, the game will
say 'Too Late!' and move on."
```
Adults:
```
"In this final part, you'll again see one item at the top of the screen.
Below it, three choices will be shown. Select the item that was originally
paired with the one on top. Be ready—each trial only lasts a few seconds.
If you don't tap the suitable choice on time, the game will say 'Too Late!'
and move on."
```
---
#### Screen 10: RecognitionScreen
**Purpose:** Multiple choice recognition test
**Components needed:**
- Cue image display (top, white box)
- Three option buttons (horizontal layout)
- Click/tap detection
- Timer (4 seconds)
- "Too Late" message overlay
- Trial counter
**Required files:**
- `components/screens/VPAM/RecognitionScreen.jsx`
- `components/shared/VPAM/RecognitionOptions.jsx`
- `hooks/vpam/useRecognitionScreen.js`
**Critical logic:**
```javascript
// For each trial:
1. Display cue image at top
2. Randomize 3 option positions:
- Correct target
- Related distractor
- Unrelated distractor
3. Start 4-second timer
4. Listen for option selection
5. On selection:
- Highlight selected option briefly
- Record choice and RT
- Validate accuracy
- Advance immediately
6. On timeout:
- Show "Too Late" for 1 second
- Record as no response (accuracy = 0)
- Advance to next trial
7. After trial 35 transition to Results
```
**Option randomization:**
```javascript
function randomizeOptions(correct, related, unrelated) {
const options = [
{ id: 'correct', image: correct, isCorrect: true },
{ id: 'related', image: related, isCorrect: false },
{ id: 'unrelated', image: unrelated, isCorrect: false }
];
// Fisher-Yates shuffle
for (let i = options.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[options[i], options[j]] = [options[j], options[i]];
}
return options;
}
```
---
#### Screen 11: ResultsScreen
**Purpose:** Display performance metrics and export data
**Components needed:**
- Performance summary cards
- Accuracy breakdown by phase
- Reaction time statistics
- Consolidation slope visualization
- Data export buttons (JSON, CSV)
- "Finish" or "Return to Test Selection" button
**Required files:**
- `components/screens/VPAM/ResultsScreen.jsx`
- `components/shared/VPAM/MetricsCard.jsx`
- `components/shared/VPAM/PhaseComparison.jsx`
- `utils/vpamCalculations.js`
- `utils/vpamDataExport.js`
**Metrics to display:**
```javascript
// Accuracy Metrics (%)
1. Immediate Recall Accuracy
2. Delayed Recall Accuracy
3. Recognition Accuracy
4. Overall Task Accuracy
// Response Metrics
5. Total Responses Given
6. Total No Responses (timeouts)
7. Correct Responses (all phases)
8. Incorrect Responses (all phases)
// Reaction Time (ms)
9. Mean RT - Immediate Recall
10. Mean RT - Delayed Recall
11. Mean RT - Recognition
12. Overall Mean RT
// Memory Change
13. Consolidation Slope (Absolute)
= Delayed Accuracy - Immediate Accuracy
14. Consolidation Slope (%)
= (Delayed - Immediate) / Immediate × 100
```
**Completion messages:**
Adolescents:
```
"That's it! You've finished this memory game. Great work!"
```
Adults:
```
"This concludes the memory task. Thank you for your participation."
```
---
## 🎨 Design Requirements
### Visual Design Principles
- **Clean, focused interface** - minimize cognitive load
- **Age-appropriate aesthetics:**
- Adolescents: Colorful gradient background, playful fonts
- Adults: Soft neutral background, professional fonts
- **Responsive:** 345px to large screens
- **Accessibility:** High contrast, clear typography
- **Minimal animations** - don't distract from memory task
### Technology Stack
- **Framework:** React with JavaScript (JSX)
- **Styling:** Tailwind CSS only (no custom CSS files)
- **Animations:** Framer Motion (minimal, subtle only)
- **State Management:** React Hooks (useState, useEffect, useRef)
- **NO localStorage/sessionStorage** - use in-memory state only
- **NO external image hosting** - images in public/images/vpam/
### Image Requirements
**Image specifications:**
```
Location: public/images/vpam/
Format: PNG or SVG
Size: ~200x200px (consistent dimensions)
Quality: High-res but optimized (<50KB each)
Background: Transparent or white
Naming: lowercase, hyphens (e.g., magic-potion.png)
Total images needed:
- Adolescents: 70 unique images (35 pairs × 2)
- Adults: 70 unique images (35 pairs × 2)
- Distractors: ~70 additional images for recognition
Total: ~210 images
```
**Image organization:**
```
public/images/vpam/
├── adolescent/
│ ├── pen.png
│ ├── kite.png
│ ├── butterfly.png
│ └── ... (70 items)
├── adult/
│ ├── mixer.png
│ ├── spectacles.png
│ ├── mobile-phone.png
│ └── ... (70 items)
└── distractors/
├── parachute.png
├── knife.png
└── ... (70 items)
```
### Stimulus Display Specifications
**Encoding Phase:**
```javascript
// Display format:
<div className="bg-white border-4 border-gray-300 rounded-lg p-8
flex items-center justify-center gap-8">
<img src={firstImage} className="w-40 h-40 object-contain" />
<img src={secondImage} className="w-40 h-40 object-contain" />
</div>
// Or stacked for mobile:
<div className="flex flex-col gap-4">
<img src={firstImage} className="w-32 h-32 object-contain" />
<img src={secondImage} className="w-32 h-32 object-contain" />
</div>
```
**Recall Phase:**
```javascript
// Cue display:
<div className="bg-white border-4 border-gray-300 rounded-lg p-8
flex items-center justify-center">
<img src={cueImage} className="w-48 h-48 object-contain" />
</div>
// Input field:
<input
type="text"
className="w-full max-w-md px-4 py-3 text-lg border-2
border-gray-400 rounded-lg focus:border-blue-500
focus:ring-2 focus:ring-blue-200"
placeholder="Type the paired item..."
maxLength="50"
/>
```
**Recognition Phase:**
```javascript
// Cue at top:
<div className="mb-8">
<img src={cueImage} className="w-32 h-32 object-contain mx-auto" />
</div>
// Three options (horizontal):
<div className="flex flex-wrap justify-center gap-4">
{options.map(option => (
<button
className="border-4 border-gray-300 rounded-lg p-4
hover:border-blue-400 active:bg-blue-50
transition-colors"
onClick={() => handleSelection(option)}
>
<img src={option.image} className="w-32 h-32 object-contain" />
</button>
))}
</div>
// Selected state:
<button className="border-4 border-blue-500 bg-blue-50 ring-4 ring-blue-200">
<img src={selectedOption.image} />
</button>
```
---
## 📊 Data Recording Requirements
### Trial Data Structure
Every trial must record:
```javascript
{
// Identification
trialNumber: number, // 1-105 (35 encoding + 35 immediate + 35 delayed + 35 recognition)
phase: 'encoding' | 'immediate_recall' | 'delayed_recall' | 'recognition',
trialInPhase: number, // 1-35 per phase
// Stimulus information
cueItem: string, // 'Kite', 'Spectacles', etc.
targetItem: string, // 'Pen', 'Mixer', etc.
distractorRelated: string | null, // 'Parachute' (recognition only)
distractorUnrelated: string | null, // 'Elephant' (recognition only)
// Response data
participantResponse: string | null, // Typed text or selected option
responseTime: number | null, // milliseconds from stimulus onset
responseAccuracy: 0 | 1, // 1 = correct, 0 = incorrect/timeout
responseType: 'typed' | 'selected' | 'timeout' | 'no-response',
// Recognition specific
selectedOption: 'correct' | 'related' | 'unrelated' | null,
optionPositions: array | null, // [0, 1, 2] randomized order
// Timing
stimulusOnsetTime: number, // timestamp
responseSubmitTime: number | null, // timestamp
encodingDuration: number | null, // encoding phase only
// Metadata
ageGroup: 'adolescent' | 'adult',
timestamp: number // Date.now()
}
```
### Summary Data Structure
After test completion:
```javascript
{
// Participant info
participantInfo: {
ageGroup: 'adolescent' | 'adult',
testDate: string,
testStartTime: string,
testEndTime: string,
totalDuration: number, // minutes
delayDurationActual: number // should be ~15 minutes
},
// Accuracy metrics (%)
accuracy: {
immediateRecall: number,
delayedRecall: number,
recognition: number,
overall: number
},
// Response counts
responseCounts: {
totalTrials: 105,
totalResponses: number,
totalTimeouts: number,
correctResponses: number,
incorrectResponses: number,
// By phase
immediateRecallAnswered: number,
delayedRecallAnswered: number,
recognitionAnswered: number
},
// Reaction time statistics (ms)
reactionTimes: {
immediateRecallMean: number,
delayedRecallMean: number,
recognitionMean: number,
overallMean: number,
// Additional stats
immediateRecallSD: number,
delayedRecallSD: number,
recognitionSD: number
},
// Memory consolidation
consolidation: {
absoluteChange: number, // Delayed - Immediate
percentageChange: number, // (Delayed - Immediate) / Immediate × 100
forgettingRate: number, // Items forgotten
itemsRetained: number // Correct in both phases
},
// Phase-specific accuracy rates
phaseAccuracy: {
immediateRecall: {
correct: number,
incorrect: number,
timeout: number,
accuracy: number // %
},
delayedRecall: {
correct: number,
incorrect: number,
timeout: number,
accuracy: number // %
},
recognition: {
correct: number,
relatedDistractorChosen: number,
unrelatedDistractorChosen: number,
timeout: number,
accuracy: number // %
}
},
// Raw trial data
trialData: [/* array of all trial records */]
}
```
### Data Export Formats
**JSON Export:**
```javascript
// Filename: vpam_results_[ageGroup]_[timestamp].json
// Full data structure with all nested objects
```
**CSV Export:**
```javascript
// Filename: vpam_results_[ageGroup]_[timestamp].csv
// Flattened trial data with column headers:
// trial_number, phase, trial_in_phase, cue_item, target_item,
// participant_response, response_time, accuracy, ...
```
---
## 🔧 Key Constants to Define
### vpamConfig.js
```javascript
export const VPAM_CONFIG = {
TOTAL_PAIRS: 35,
PHASES: ['encoding', 'immediate_recall', 'delayed_recall', 'recognition'],
TIMING: {
// Encoding
ENCODING_DURATION_ADOLESCENT: 3500, // ms
ENCODING_DURATION_ADULT: 2500, // ms
INTER_PAIR_INTERVAL: 300, // ms blank screen between pairs
// Recall phases
RECALL_RESPONSE_WINDOW: 15000, // ms (both age groups)
TIMEOUT_MESSAGE_DURATION: 1000, // ms
// Recognition phase
RECOGNITION_RESPONSE_WINDOW: 4000, // ms (both age groups)
TOO_LATE_MESSAGE_DURATION: 1000, // ms
// Delay interval
DELAY_DURATION: 900000, // ms (15 minutes)
},
FILLER_TASKS: [
'response_inhibition',
'cognitive_flexibility',
'stroop' // if available
],
VALIDATION: {
MAX_INPUT_LENGTH: 50,
CASE_SENSITIVE: false,
TRIM_WHITESPACE: true,
ALLOW_TYPOS: false // set to true for lenient matching
}
};
```
### vpamInstructions.js
```javascript
export const VPAM_INSTRUCTIONS = {
adolescent: {
intro: {
title: "Memory Game: Picture Pairs",
description: `In this game, you will see pictures of everyday things.
Some of these pictures will be shown together as pairs. Your task is
to pay close attention and try to remember which ones are being
presented as pairs, because later we will test your memory in different
ways. Sometimes you will have to write the missing item, and sometimes
you will choose it from a few options. Let's get started!`,
buttonText: "Let's Go!"
},
encoding: {
title: "Learning Phase",
description: `You will see two pictures appear inside a box on the screen.
Just look carefully and try to remember which pictures are being
presented as pairs. You don't need to press anything. Each pair will
disappear after a few seconds, so focus while it is on the screen.`,
buttonText: "Let's Go!"
},
immediateRecall: {
title: "Memory Test: Part 1",
description: `Great job learning the pairs! Now, one item from each pair
will appear by itself. Your task is to write the item that goes with it.
Try to answer quickly — you'll have a short time for each one.`,
reminder: `Remember: write the exact item that was paired. Don't just
write a general category, color, or size — focus on the specific item.`,
example: `Example: If you see 🍎 Apple and it was paired with 🪑 Chair,
write 'Chair', not 'furniture' or 'brown chair' or 'big chair'.`,
buttonText: "Let's Go!"
},
delayTransition: {
title: "Brain Break!",
description: `Great job looking at all the pairs! Before we test your
memory, you'll play a few short brain-teaser games. These games are
like a quick workout for your mind. Once you're done, we'll bring you
back to check how many pairs you can remember!`,
buttonText: "Let's Go!"
},
delayedRecall: {
title: "Memory Test: Part 2",
description: `Welcome back to the memory game you played earlier! Remember,
you saw pairs of items and tried to learn which ones go together. Now,
again, one item from each pair will appear alone. Your task is to write
the item that goes with it. You'll have a short time for each one, so
try to answer quickly.`,
reminder: `Write the exact item that goes with the one you see. Don't just
write a general category, color, or size of the object — try to remember
the specific pair.`,
buttonText: "Let's Go!"
},
recognition: {
title: "Memory Test: Final Part",
description: `Next, you'll see one picture at the top of the screen. Below
it, you'll see three choices. Your job is to pick the picture that was
originally paired with the one on top. Be quick—you'll only have a few
seconds for each choice.`,
buttonText: "Let's Go!"
},
completion: {
title: "Awesome Work!",
message: "That's it! You've finished this memory game. Great work!",
buttonText: "View Results"
}
},
adult: {
intro: {
title: "Visual Paired Associates Memory Test",
description: `In this task, you will see images of everyday objects.
Some of these images will be presented together as pairs. Your task is
to observe carefully and remember which items are paired together, as
your memory will be tested in different ways. You will sometimes need
to type the missing item, and other times select it from multiple options.`,
buttonText: "Begin Task"
},
encoding: {
title: "Learning Phase",
description: `You will see two items presented together inside a box. Your
task is to observe carefully and remember which items are being presented
as pairs. You don't need to press anything. Each pair will only remain on
screen briefly, so focus while it is shown.`,
buttonText: "Start Learning"
},
immediateRecall: {
title: "Immediate Recall Test",
description: `You've just seen all the pairs. Now, a single item from each
pair will appear alone. Your task is to type or write the item that was
originally paired with it. Respond quickly — each trial has a time limit.`,
reminder: `Type the exact item that was paired. Do not write a general
category, color, or size — focus on the specific item.`,
example: `Example: If the cue is 🖊️ Pen and it was paired with 🐘 Elephant,
type 'Elephant', not 'animal', 'creature', or 'grey elephant'.`,
buttonText: "Begin Recall"
},
delayTransition: {
title: "Interim Activities",
description: `Well done—you've completed the first part. Next, you'll do a
few short thinking activities designed to keep your mind active while your
memory continues to work in the background. After that, we'll return to
test how well you remember the pairs.`,
buttonText: "Continue"
},
delayedRecall: {
title: "Delayed Recall Test",
description: `We're returning to the memory task you did before. Earlier,
you learned pairs of items and tried to remember which ones belonged
together. In this part, again, a single item from each pair will appear
alone. Your task is to type or write the item that was originally paired
with it.`,
reminder: `Type the exact item that was paired with the cue you see. Do not
write a general category, color, or size of the object — focus on the
specific paired item.`,
buttonText: "Begin Test"
},
recognition: {
title: "Recognition Test",
description: `In this final part, you'll again see one item at the top of
the screen. Below it, three choices will be shown. Select the item that
was originally paired with the one on top. Be ready—each trial only lasts
a few seconds.`,
buttonText: "Begin Recognition"
},
completion: {
title: "Task Complete",
message: "This concludes the memory task. Thank you for your participation.",
buttonText: "View Results"
}
}
};
```
### vpamPairs.js
```javascript
// EXACT sequences from PDF
export const VPAM_PAIRS = {
adolescent: [
{ id: 1, first: 'Pen', second: 'Kite', firstImg: 'pen.png', secondImg: 'kite.png' },
{ id: 2, first: 'Butterfly', second: 'Spoon', firstImg: 'butterfly.png', secondImg: 'spoon.png' },
// ... all 35 pairs
],
adult: [
{ id: 1, first: 'Mixer', second: 'Spectacles', firstImg: 'mixer.png', secondImg: 'spectacles.png' },
{ id: 2, first: 'Mobile Phone', second: 'Water Tap', firstImg: 'mobile-phone.png', secondImg: 'water-tap.png' },
// ... all 35 pairs
]
};
// Immediate recall cues (show SECOND, ask for FIRST)
export const IMMEDIATE_RECALL_CUES = {
adolescent: [
{ id: 1, cue: 'Kite', cueImg: 'kite.png', correctAnswer: 'Pen', correctImg: 'pen.png' },
{ id: 2, cue: 'Butterfly', cueImg: 'butterfly.png', correctAnswer: 'Spoon', correctImg: 'spoon.png' },
// ... all 35 trials
],
adult: [
{ id: 1, cue: 'Spectacles', cueImg: 'spectacles.png', correctAnswer: 'Mixer', correctImg: 'mixer.png' },
// ... all 35 trials
]
};
// Delayed recall cues (show FIRST, ask for SECOND)
export const DELAYED_RECALL_CUES = {
adolescent: [
{ id: 1, cue: 'Pen', cueImg: 'pen.png', correctAnswer: 'Kite', correctImg: 'kite.png' },
// ... all 35 trials
],
adult: [
{ id: 1, cue: 'Mixer', cueImg: 'mixer.png', correctAnswer: 'Spectacles', correctImg: 'spectacles.png' },
// ... all 35 trials
]
};
// Recognition trials with distractors
export const RECOGNITION_TRIALS = {
adolescent: [
{
id: 1,
cue: 'Pen',
cueImg: 'pen.png',
correctTarget: 'Kite',
correctImg: 'kite.png',
relatedDistractor: 'Parachute',
relatedImg: 'parachute.png',
unrelatedDistractor: 'Elephant',
unrelatedImg: 'elephant.png'
},
// ... all 35 trials with distractors
],
adult: [
{
id: 1,
cue: 'Mixer',
cueImg: 'mixer.png',
correctTarget: 'Spectacles',
correctImg: 'spectacles.png',
relatedDistractor: 'Sunglasses',
relatedImg: 'sunglasses.png',
unrelatedDistractor: 'Apple',
unrelatedImg: 'apple.png'
},
// ... all 35 trials
]
};
```
---
## 📁 File Structure Requirements
```
src/
├── components/
│ ├── screens/
│ │ ├── VPAM/
│ │ │ ├── IntroScreen.jsx
│ │ │ ├── EncodingInstructionScreen.jsx
│ │ │ ├── EncodingScreen.jsx
│ │ │ ├── ImmediateRecallInstructionScreen.jsx
│ │ │ ├── ImmediateRecallScreen.jsx
│ │ │ ├── DelayIntervalScreen.jsx
│ │ │ ├── DelayedRecallInstructionScreen.jsx
│ │ │ ├── DelayedRecallScreen.jsx
│ │ │ ├── RecognitionInstructionScreen.jsx
│ │ │ ├── RecognitionScreen.jsx
│ │ │ ├── ResultsScreen.jsx
│ │ │ └── VisualPairedAssociatesTest.jsx (main orchestrator)
│ │ │
│ │ ├── CFT/ # Existing
│ │ ├── RIT/ # Existing
│ │ └── TestSelectionScreen.jsx
│ │
│ └── shared/
│ └── VPAM/
│ ├── PairDisplay.jsx
│ ├── RecallInput.jsx
│ ├── RecognitionOptions.jsx
│ ├── TrialCounter.jsx
│ ├── Timer.jsx
│ ├── MetricsCard.jsx
│ └── PhaseComparison.jsx
├── hooks/
│ └── vpam/
│ ├── useEncodingScreen.js
│ ├── useRecallScreen.js
│ ├── useRecognitionScreen.js
│ └── useDelayInterval.js
├── utils/
│ ├── vpamTimer.js
│ ├── vpamValidation.js
│ ├── vpamCalculations.js
│ ├── vpamDataExport.js
│ └── vpamAnimations.js
├── constants/
│ ├── vpamConfig.js
│ ├── vpamInstructions.js
│ ├── vpamPairs.js
│ └── testsConfig.js (update to include VPAM)
└── public/
└── images/
└── vpam/
├── adolescent/
│ ├── pen.png
│ ├── kite.png
│ └── ... (70 images)
├── adult/
│ ├── mixer.png
│ ├── spectacles.png
│ └── ... (70 images)
└── distractors/
├── parachute.png
├── knife.png
└── ... (70 images)
```
---
## 🚫 Important Constraints
### NEVER Do This
1. ❌ Change pair order (must follow PDF exactly)
2. ❌ Show feedback on correctness during test
3. ❌ Allow skipping trials
4. ❌ Let participants replay encoding phase
5. ❌ Accept category answers (require specific items)
6. ❌ Use emojis as actual stimuli (use real images)
7. ❌ Skip or abbreviate delay interval
8. ❌ Randomize recall cue order (follow PDF)
9. ❌ Show scores during test (only at end)
10. ❌ Use localStorage or sessionStorage
### ALWAYS Do This
1. ✅ Follow exact pair sequences from PDF
2. ✅ Use age-specific timing (3.5s vs 2.5s encoding)
3. ✅ Show "Time is up!" / "Too Late" on timeout
4. ✅ Validate exact item names only
5. ✅ Randomize recognition option positions
6. ✅ Track all metrics silently during test
7. ✅ Implement 15-minute delay with filler tasks
8. ✅ Use opposite cues for delayed vs immediate recall
9. ✅ Display clear, high-contrast images
10. ✅ Export complete data at end
---
## 🔧 Development Workflow
### Step-by-Step Process
1. **Current Phase:** Developer specifies which screen to create
2. **AI Creates:** Complete screen with all required files
3. **AI Shows:** Code for that screen only
4. **AI Asks:** "Screen [Name] complete. Proceed to [NextScreen]?"
5. **Developer:** Approves or requests changes
6. **Repeat:** Until all 11 screens are complete
7. **Integration:** Connect VPAM to TestSelectionScreen
8. **Testing:** Verify timing, data collection, export
### Code Quality Standards
- Use functional components with hooks
- Separate concerns (logic in hooks, UI in components)
- Add JSDoc comments for complex functions
- Follow consistent naming conventions (camelCase)
- Use Tailwind for ALL styling (no inline styles)
- Handle edge cases (timeout, rapid input, empty responses)
- Create reusable components (don't duplicate code)
- Optimize re-renders with useMemo/useCallback
- Implement proper cleanup in useEffect
### State Management Pattern
```javascript
// Main VPAM Test State (Context or prop drilling)
const [testState, setTestState] = useState({
currentScreen: 'intro', // 'intro', 'encoding', 'immediateRecall', etc.
ageGroup: null, // 'adolescent' or 'adult'
phase: null, // 'encoding', 'immediate_recall', 'delayed_recall', 'recognition'
currentTrial: 0, // 0-34 per phase
trialData: [], // All recorded trials
startTime: null,
delayStartTime: null,
delayEndTime: null
});
// Per-Screen Local State
const [screenState, setScreenState] = useState({
showStimulus: false,
currentPair: null,
userResponse: '',
isSubmitting: false,
showTimeout: false,
reactionStartTime: null
});
```
---
## 🎭 Animation Specifications
### Framer Motion Animations (utils/vpamAnimations.js)
```javascript
// Minimal, non-distracting animations
export const fadeIn = {
initial: { opacity: 0 },
animate: { opacity: 1 },
transition: { duration: 0.3 }
};
export const slideUp = {
initial: { y: 20, opacity: 0 },
animate: { y: 0, opacity: 1 },
transition: { duration: 0.4, ease: 'easeOut' }
};
export const pairTransition = {
initial: { opacity: 0, scale: 0.95 },
animate: { opacity: 1, scale: 1 },
exit: { opacity: 0, scale: 0.95 },
transition: { duration: 0.2 }
};
export const timeoutPulse = {
initial: { scale: 1 },
animate: {
scale: [1, 1.1, 1],
opacity: [1, 0.8, 0]
},
transition: { duration: 1 }
};
// NO complex animations during encoding/recall
// Keep cognitive load minimal
```
---
## 🎯 Timing Flow (CRITICAL)
### Encoding Phase Timing
```javascript
// For each of 35 pairs:
1. Display pair immediately (no fade-in delay)
- Both images visible simultaneously
- Centered in white box
2. Hold for exposure duration
- Adolescent: 3.5 seconds
- Adult: 2.5 seconds
- No user interaction
3. Brief blank screen (0.3 seconds)
- Inter-pair interval
- Prevents visual overlap
4. Next pair appears
- Repeat steps 1-3
5. After pair 35 transition to Immediate Recall
- No delay, automatic progression
// Total encoding time:
// Adolescents: (3.5s + 0.3s) × 35 = 133 seconds (~2.2 min)
// Adults: (2.5s + 0.3s) × 35 = 98 seconds (~1.6 min)
```
### Recall Phase Timing
```javascript
// For each of 35 trials:
1. Display cue image immediately
- Start reaction timer
- Show text input field (empty)
2. Wait for response OR timeout (15 seconds)
- Listen for:
* Text input changes
* Submit button click
* Enter key press
* Timer expiration
3. On Submit (before timeout):
- Record response text
- Calculate reaction time
- Validate accuracy
- Clear input field
- Proceed to next trial immediately
4. On Timeout (no submit):
- Show "Time is up!" (1 second)
- Record as no response (accuracy = 0)
- Clear input field
- Proceed to next trial
5. Brief blank screen (optional, 0.3s)
- Or immediately show next cue
// Total recall time (worst case - all timeouts):
// (15s + 1s) × 35 = 560 seconds (~9.3 min per phase)
```
### Recognition Phase Timing
```javascript
// For each of 35 trials:
1. Display cue at top
2. Display 3 randomized options below
3. Start 4-second timer
4. Wait for selection OR timeout
5. On Selection (before timeout):
- Highlight selected option briefly (0.2s)
- Record choice and RT
- Validate accuracy
- Proceed to next trial immediately
6. On Timeout (no selection):
- Show "Too Late" (1 second)
- Record as no response (accuracy = 0)
- Proceed to next trial
// Total recognition time (worst case):
// (4s + 1s) × 35 = 175 seconds (~2.9 min)
```
### Delay Interval Timing
```javascript
// 15-minute delay with filler tasks
1. Show transition message (5 seconds)
2. Launch Response Inhibition Test (~7 min)
3. Launch Cognitive Flexibility Test (~6 min)
4. Launch Stroop Test (~2 min) [if available]
5. Auto-trigger Delayed Recall at 15:00
// Critical: Track elapsed time precisely
// Use Date.now() or performance.now()
// Don't rely on setTimeout for long durations
```
---
## 📋 Scoring Logic (CRITICAL)
### Response Validation
```javascript
/**
* Validates user response against correct answer
* @param {string} userInput - Raw user input
* @param {string} correctAnswer - Expected answer
* @returns {boolean} - True if correct
*/
function validateResponse(userInput, correctAnswer) {
// Normalize both strings
const normalized = userInput
.toLowerCase()
.trim()
.replace(/[^a-z0-9\s]/g, ''); // Remove punctuation
const correct = correctAnswer
.toLowerCase()
.trim()
.replace(/[^a-z0-9\s]/g, '');
// Exact match required
if (normalized === correct) {
return true;
}
// Optional: Handle common variations
// "lady's finger" vs "ladys finger" vs "ladies finger"
const variations = generateVariations(correct);
return variations.includes(normalized);
}
/**
* Generate acceptable variations for hyphenated/possessive words
*/
function generateVariations(word) {
return [
word,
word.replace(/[\s-']/g, ''), // Remove spaces, hyphens, apostrophes
word.replace(/'/g, ''), // Remove apostrophes only
word.replace(/-/g, ' '), // Replace hyphens with spaces
word.replace(/\s/g, '') // Remove all spaces
];
}
```
### Accuracy Calculation
```javascript
/**
* Calculate accuracy metrics for each phase
*/
function calculateAccuracy(trialData, phase) {
const phaseTrials = trialData.filter(t => t.phase === phase);
const totalTrials = phaseTrials.length;
const answered = phaseTrials.filter(t => t.responseType !== 'timeout').length;
const correct = phaseTrials.filter(t => t.responseAccuracy === 1).length;
return {
totalTrials,
answered,
notAnswered: totalTrials - answered,
correct,
incorrect: answered - correct,
accuracyRate: totalTrials > 0 ? (correct / totalTrials) * 100 : 0,
answeredAccuracyRate: answered > 0 ? (correct / answered) * 100 : 0
};
}
/**
* Calculate overall task metrics
*/
function calculateOverallMetrics(trialData) {
const immediateRecall = calculateAccuracy(trialData, 'immediate_recall');
const delayedRecall = calculateAccuracy(trialData, 'delayed_recall');
const recognition = calculateAccuracy(trialData, 'recognition');
// Consolidation slope
const absoluteChange = delayedRecall.accuracyRate - immediateRecall.accuracyRate;
const percentageChange = immediateRecall.accuracyRate > 0
? (absoluteChange / immediateRecall.accuracyRate) * 100
: 0;
// Overall accuracy
const totalCorrect = immediateRecall.correct + delayedRecall.correct + recognition.correct;
const totalTrials = immediateRecall.totalTrials + delayedRecall.totalTrials + recognition.totalTrials;
const overallAccuracy = totalTrials > 0 ? (totalCorrect / totalTrials) * 100 : 0;
return {
immediateRecall,
delayedRecall,
recognition,
consolidation: {
absoluteChange,
percentageChange,
forgettingRate: Math.max(0, -absoluteChange), // Only if negative
itemsRetained: Math.min(immediateRecall.correct, delayedRecall.correct)
},
overall: {
accuracy: overallAccuracy,
totalCorrect,
totalTrials,
totalAnswered: immediateRecall.answered + delayedRecall.answered + recognition.answered
}
};
}
```
### Reaction Time Calculation
```javascript
/**
* Calculate reaction time statistics
*/
function calculateReactionTimes(trialData, phase) {
const phaseTrials = trialData
.filter(t => t.phase === phase && t.responseTime !== null);
if (phaseTrials.length === 0) {
return { mean: null, median: null, sd: null, min: null, max: null };
}
const times = phaseTrials.map(t => t.responseTime);
const mean = times.reduce((a, b) => a + b, 0) / times.length;
// Standard deviation
const variance = times.reduce((sum, time) => {
return sum + Math.pow(time - mean, 2);
}, 0) / times.length;
const sd = Math.sqrt(variance);
// Median
const sorted = [...times].sort((a, b) => a - b);
const median = sorted.length % 2 === 0
? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2
: sorted[Math.floor(sorted.length / 2)];
return {
mean: Math.round(mean),
median: Math.round(median),
sd: Math.round(sd),
min: Math.min(...times),
max: Math.max(...times),
count: times.length
};
}
```
---
## 🎨 Component Examples
### PairDisplay Component
```javascript
// components/shared/VPAM/PairDisplay.jsx
import React from 'react';
import { motion } from 'framer-motion';
/**
* Displays a pair of images during encoding phase
*/
export default function PairDisplay({ firstImage, secondImage, ageGroup }) {
const containerBg = ageGroup === 'adolescent'
? 'bg-gradient-to-br from-purple-100 to-blue-100'
: 'bg-gray-50';
return (
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{ duration: 0.2 }}
className={`${containerBg} min-h-screen flex items-center justify-center p-4`}
>
<div className="bg-white border-4 border-gray-300 rounded-2xl p-8 shadow-lg">
<div className="flex flex-col md:flex-row items-center justify-center gap-8 md:gap-12">
<img
src={firstImage}
alt="First item"
className="w-40 h-40 md:w-48 md:h-48 object-contain"
/>
<div className="text-4xl text-gray-400 font-bold">+</div>
<img
src={secondImage}
alt="Second item"
className="w-40 h-40 md:w-48 md:h-48 object-contain"
/>
</div>
</div>
</motion.div>
);
}
```
### RecallInput Component
```javascript
// components/shared/VPAM/RecallInput.jsx
import React, { useState, useEffect, useRef } from 'react';
import { motion } from 'framer-motion';
/**
* Input component for recall phases
*/
export default function RecallInput({
cueImage,
onSubmit,
timeLimit = 15000,
showTimeout,
disabled
}) {
const [input, setInput] = useState('');
const [timeRemaining, setTimeRemaining] = useState(timeLimit / 1000);
const inputRef = useRef(null);
useEffect(() => {
// Focus input on mount
inputRef.current?.focus();
}, [cueImage]);
useEffect(() => {
// Countdown timer
const interval = setInterval(() => {
setTimeRemaining(prev => Math.max(0, prev - 0.1));
}, 100);
return () => clearInterval(interval);
}, []);
const handleSubmit = (e) => {
e.preventDefault();
if (input.trim() && !disabled) {
onSubmit(input.trim());
setInput('');
}
};
const progressPercent = (timeRemaining / (timeLimit / 1000)) * 100;
const isUrgent = timeRemaining < 5;
return (
<div className="flex flex-col items-center gap-6">
{/* Cue Image */}
<div className="bg-white border-4 border-gray-300 rounded-2xl p-6 shadow-lg">
<img
src={cueImage}
alt="Cue"
className="w-48 h-48 object-contain"
/>
</div>
{/* Timer Bar */}
<div className="w-full max-w-md h-2 bg-gray-200 rounded-full overflow-hidden">
<motion.div
className={`h-full ${isUrgent ? 'bg-red-500' : 'bg-blue-500'}`}
initial={{ width: '100%' }}
animate={{ width: `${progressPercent}%` }}
transition={{ duration: 0.1 }}
/>
</div>
{/* Input Form */}
<form onSubmit={handleSubmit} className="w-full max-w-md">
<input
ref={inputRef}
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
disabled={disabled}
placeholder="Type the paired item..."
maxLength={50}
className="w-full px-6 py-4 text-lg border-3 border-gray-400
rounded-xl focus:border-blue-500 focus:ring-4
focus:ring-blue-200 outline-none transition-all
disabled:bg-gray-100 disabled:cursor-not-allowed"
/>
<button
type="submit"
disabled={!input.trim() || disabled}
className="w-full mt-4 px-6 py-4 text-lg font-semibold
bg-blue-500 text-white rounded-xl
hover:bg-blue-600 active:scale-95
disabled:bg-gray-300 disabled:cursor-not-allowed
transition-all"
>
Submit Answer
</button>
</form>
{/* Timeout Message */}
{showTimeout && (
<motion.div
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.8, opacity: 0 }}
className="fixed inset-0 flex items-center justify-center
bg-black bg-opacity-50 z-50"
>
<div className="bg-white px-12 py-8 rounded-2xl shadow-2xl">
<p className="text-3xl font-bold text-red-600">Time is up!</p>
</div>
</motion.div>
)}
</div>
);
}
```
### RecognitionOptions Component
```javascript
// components/shared/VPAM/RecognitionOptions.jsx
import React, { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
/**
* Three-option selection for recognition phase
*/
export default function RecognitionOptions({
cueImage,
options, // [{ id, image, isCorrect }, ...]
onSelect,
timeLimit = 4000,
showTimeout,
disabled
}) {
const [timeRemaining, setTimeRemaining] = useState(timeLimit / 1000);
const [selectedId, setSelectedId] = useState(null);
useEffect(() => {
const interval = setInterval(() => {
setTimeRemaining(prev => Math.max(0, prev - 0.1));
}, 100);
return () => clearInterval(interval);
}, []);
const handleSelect = (option) => {
if (disabled || selectedId) return;
setSelectedId(option.id);
setTimeout(() => {
onSelect(option);
}, 200); // Brief highlight before advancing
};
const progressPercent = (timeRemaining / (timeLimit / 1000)) * 100;
const isUrgent = timeRemaining < 2;
return (
<div className="flex flex-col items-center gap-8">
{/* Cue Image */}
<div className="bg-white border-4 border-gray-300 rounded-2xl p-6 shadow-lg">
<img
src={cueImage}
alt="Cue"
className="w-32 h-32 object-contain"
/>
</div>
{/* Timer Bar */}
<div className="w-full max-w-2xl h-3 bg-gray-200 rounded-full overflow-hidden">
<motion.div
className={`h-full ${isUrgent ? 'bg-red-500' : 'bg-green-500'}`}
initial={{ width: '100%' }}
animate={{ width: `${progressPercent}%` }}
transition={{ duration: 0.1 }}
/>
</div>
{/* Options */}
<div className="flex flex-wrap justify-center gap-6">
{options.map((option) => (
<motion.button
key={option.id}
onClick={() => handleSelect(option)}
disabled={disabled}
whileHover={{ scale: disabled ? 1 : 1.05 }}
whileTap={{ scale: disabled ? 1 : 0.95 }}
className={`
border-4 rounded-2xl p-4 transition-all
${selectedId === option.id
? 'border-blue-500 bg-blue-50 ring-4 ring-blue-200'
: 'border-gray-300 bg-white hover:border-blue-400'
}
${disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'}
`}
>
<img
src={option.image}
alt="Option"
className="w-32 h-32 object-contain"
/>
</motion.button>
))}
</div>
{/* Timeout Message */}
{showTimeout && (
<motion.div
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.8, opacity: 0 }}
className="fixed inset-0 flex items-center justify-center
bg-black bg-opacity-50 z-50"
>
<div className="bg-white px-12 py-8 rounded-2xl shadow-2xl">
<p className="text-3xl font-bold text-orange-600">Too Late!</p>
</div>
</motion.div>
)}
</div>
);
}
```
---
## 📊 Data Export Implementation
### vpamDataExport.js
```javascript
/**
* Export VPAM test results in multiple formats
*/
/**
* Export as JSON file
*/
export function exportJSON(data, ageGroup) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `vpam_results_${ageGroup}_${timestamp}.json`;
const jsonStr = JSON.stringify(data, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
downloadBlob(blob, filename);
}
/**
* Export as CSV file
*/
export function exportCSV(data, ageGroup) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `vpam_results_${ageGroup}_${timestamp}.csv`;
// CSV Headers
const headers = [
'Trial_Number',
'Phase',
'Trial_In_Phase',
'Cue_Item',
'Target_Item',
'Participant_Response',
'Response_Time_ms',
'Accuracy',
'Response_Type',
'Selected_Option',
'Timestamp'
];
// Convert trial data to CSV rows
const rows = data.trialData.map(trial => [
trial.trialNumber,
trial.phase,
trial.trialInPhase,
trial.cueItem || 'N/A',
trial.targetItem,
trial.participantResponse || '',
trial.responseTime || '',
trial.responseAccuracy,
trial.responseType,
trial.selectedOption || 'N/A',
trial.timestamp
]);
// Combine headers and rows
const csvContent = [
headers.join(','),
...rows.map(row => row.map(escapeCSV).join(','))
].join('\n');
const blob = new Blob([csvContent], { type: 'text/csv' });
downloadBlob(blob, filename);
}
/**
* Escape CSV values
*/
function escapeCSV(value) {
if (value === null || value === undefined) return '';
const str = String(value);
if (str.includes(',') || str.includes('"') || str.includes('\n')) {
return `"${str.replace(/"/g, '""')}"`;
}
return str;
}
/**
* Trigger browser download
*/
function downloadBlob(blob, filename) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
/**
* Export summary report (human-readable)
*/
export function exportSummaryReport(data, ageGroup) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `vpam_summary_${ageGroup}_${timestamp}.txt`;
const report = `
VISUAL PAIRED ASSOCIATES MEMORY TEST - SUMMARY REPORT
====================================================
Test Information:
-----------------
Age Group: ${ageGroup === 'adolescent' ? 'Adolescent (14-18)' : 'Adult (18-22)'}
Test Date: ${data.participantInfo.testDate}
Total Duration: ${data.participantInfo.totalDuration} minutes
Delay Duration: ${data.participantInfo.delayDurationActual} minutes
Overall Performance:
--------------------
Total Trials: ${data.responseCounts.totalTrials}
Total Responses: ${data.responseCounts.totalResponses}
Correct Responses: ${data.responseCounts.correctResponses}
Overall Accuracy: ${data.accuracy.overall.toFixed(2)}%
Phase-Specific Accuracy:
------------------------
Immediate Recall: ${data.accuracy.immediateRecall.toFixed(2)}%
Delayed Recall: ${data.accuracy.delayedRecall.toFixed(2)}%
Recognition: ${data.accuracy.recognition.toFixed(2)}%
Reaction Times (Mean):
----------------------
Immediate Recall: ${data.reactionTimes.immediateRecallMean}ms
Delayed Recall: ${data.reactionTimes.delayedRecallMean}ms
Recognition: ${data.reactionTimes.recognitionMean}ms
Memory Consolidation:
---------------------
Absolute Change: ${data.consolidation.absoluteChange.toFixed(2)}%
Percentage Change: ${data.consolidation.percentageChange.toFixed(2)}%
Items Retained: ${data.consolidation.itemsRetained} / 35
====================================================
`.trim();
const blob = new Blob([report], { type: 'text/plain' });
downloadBlob(blob, filename);
}
```
---
## 🔍 Testing Checklist
### Before Declaring Complete
- [ ] **All 11 screens functional** and transition properly
- [ ] **Timing accuracy** verified with stopwatch
- [ ] Encoding: 3.5s (adolescent) / 2.5s (adult) per pair
- [ ] Recall: 15s response window
- [ ] Recognition: 4s response window
- [ ] Delay: Exactly 15 minutes
- [ ] **Image loading** works for all 210+ images
- [ ] **Response validation** correctly identifies exact matches
- [ ] **Data recording** captures all required fields
- [ ] **Timeout messages** display correctly
- [ ] **Recognition randomization** works (options in different positions)
- [ ] **Calculations correct** for all metrics
- [ ] **Export functions** produce valid JSON/CSV files
- [ ] **Age-specific content** displays properly for both groups
- [ ] **Responsive design** works on mobile (345px) to desktop
- [ ] **No console errors** or warnings
- [ ] **Memory leaks** prevented (proper cleanup in useEffect)
- [ ] **Keyboard navigation** works (Enter to submit, Tab through options)
- [ ] **Accessibility** basics (alt text, ARIA labels, focus indicators)
---
## 🎓 Integration with Existing Project
### Update TestSelectionScreen
```javascript
// components/screens/TestSelectionScreen.jsx
const tests = [
{
id: 'rit',
name: 'Response Inhibition Task',
description: 'Go/No-Go test measuring impulse control',
component: ResponseInhibitionTest,
estimatedTime: '8-10 minutes'
},
{
id: 'cft',
name: 'Cognitive Flexibility Test',
description: 'Tests ability to switch between rules',
component: CognitiveFlexibilityTest,
estimatedTime: '10-12 minutes'
},
{
id: 'vpam', // NEW
name: 'Visual Paired Associates Memory',
description: 'Tests associative memory and retention',
component: VisualPairedAssociatesTest,
estimatedTime: '30-35 minutes'
}
];
```
### Update testsConfig.js
```javascript
// constants/testsConfig.js
export const TESTS_CONFIG = {
rit: {
name: 'Response Inhibition Task',
shortName: 'RIT',
route: '/rit',
color: 'blue'
},
cft: {
name: 'Cognitive Flexibility Test',
shortName: 'CFT',
route: '/cft',
color: 'purple'
},
vpam: { // NEW
name: 'Visual Paired Associates Memory',
shortName: 'VPAM',
route: '/vpam',
color: 'green'
}
};
```
---
## 📝 Final Notes
### Research Validity Reminders
- This is a **standardized memory test** - ANY deviation from specifications invalidates research data
- Timing must be **precise to the millisecond** where possible
- Trial order is **predetermined, not randomized** - follow PDF exactly
- Response validation must be **strict** (exact item names only)
- Data export must include **ALL metrics** for statistical analysis
### Performance Optimization
- Preload ALL images before starting encoding phase
- Use `React.memo()` for heavy components
- Debounce text input validation (but record raw input)
- Clear timers and intervals properly to prevent memory leaks
- Consider using Web Workers for data calculations if needed
### Accessibility Considerations
- Keyboard navigation for all inputs
- Screen reader compatibility (ARIA labels)
- High contrast mode support
- Focus indicators clearly visible
- Text size adjustable (relative units)
### Future Enhancements (Optional)
- Practice trials for recall/recognition phases
- Audio cues (optional mode)
- Multi-language support
- Adaptive difficulty (not standard, research variant)
- Real-time data sync to server
- Progress save/resume functionality
---
## ✅ Development Completion Criteria
The VPAM test is considered complete when:
1. ✅ All 11 screens implemented and functional
2. ✅ All timing specifications met precisely
3. ✅ All 210+ images loaded and displayed correctly
4. ✅ Data recording captures all required metrics
5. ✅ Export functions produce valid, complete data files
6. ✅ Age-specific content displays correctly
7. ✅ Responsive design works across all screen sizes
8. ✅ No bugs, errors, or console warnings
9. ✅ Code is clean, commented, and maintainable
10. ✅ Integration with existing project seamless
11. ✅ Testing checklist 100% verified
12. ✅ Documentation updated
---
**IMPORTANT REMINDERS:**
- **ONE SCREEN AT A TIME** - wait for:**
- `components/screens/VPAM/IntroScreen.jsx`
- `constants/vpamInstructions.js`
**Content:**
```javascript
// Generic welcome message (shown to all)
"In this game, you will see pictures of everyday things. Some of these
pictures will be shown together as pairs. Your task is to pay close
attention and try to remember which ones are being presented as pairs,
because later we will test your memory in different ways. Sometimes you
will have to write the missing item, and sometimes you will choose it
from a few options. Let's get started!"
```
**State to initialize:**
- `ageGroup` (null → 'adolescent' or 'adult')
- `currentScreen` ('intro')
---
#### Screen 2: EncodingInstructionScreen
**Purpose:** Explain the learning phase before showing pairs
**Components needed:**
- Instruction text display
- Example pair visualization
- Duration explanation
- "Let's Go!" button
**Required files:**
- `components/screens/VPAM/EncodingInstructionScreen.jsx`
**Instructions:**
Adolescents:
```
"You will see two pictures appear inside a box on the screen. Just look
carefully and try to remember which pictures are being presented as pairs.
You don't need to press anything. Each pair will disappear after a few
seconds, so focus while it is on the screen."
```
Adults:
```
"You will see two items presented together inside a box. Your task is to
observe carefully and remember which items are being presented as pairs.
You don't need to press anything. Each pair will only remain on screen
briefly, so focus while it is shown."
```
---
#### Screen 3: EncodingScreen
**Purpose:** Display all 35 pairs for learning
**Components needed:**
- White box container (centered)
- Two image displays (side by side)
- Automatic timer
- Progress indicator (optional: "Pair 12 of 35")
- Auto-advance logic
**Required files:**
- `components/screens/VPAM/EncodingScreen.jsx`
- `components/shared/VPAM/PairDisplay.jsx`
- `hooks/vpam/useEncodingScreen.js`
- `utils/vpamTimer.js`
**Critical logic:**
```javascript
// For each pair in sequence:
1. Display both images together
2. Start timer (3.5s adolescent / 2.5s adult)
3. Wait for timer completion (NO user input)
4. Clear screen briefly
5. Load next pair
6. After pair 35 transition to Immediate Recall
```
**Timing precision:**
- Use `setTimeout` or `setInterval`
- Track exposure time per pair
- Record timestamp for each pair shown
---
#### Screen 4: ImmediateRecallInstructionScreen
**Purpose:** Explain the typing recall task
**Components needed:**
- Instruction text display
- Example with visual
- Response format explanation
- "Let's Go!" button
**Required files:**
- `components/screens/VPAM/ImmediateRecallInstructionScreen.jsx`
**Instructions:**
Adolescents:
```
"Great job learning the pairs! Now, one item from each pair will appear
by itself. Your task is to write the item that goes with it. Try to answer
quickly — you'll have a short time for each one.
Remember: write the exact item that was paired. Don't just write a general
category, color, or size — focus on the specific item.
Example: If you see 🍎 Apple and it was paired with 🪑 Chair, write 'Chair',
not 'furniture' or 'brown chair' or 'big chair'."
```
Adults:
```
"You've just seen all the pairs. Now, a single item from each pair will
appear alone. Your task is to type or write the item that was originally
paired with it. Respond quickly — each trial has a time limit.
Type the exact item that was paired. Do not write a general category, color,
or size — focus on the specific item.
Example: If the cue is 🖊️ Pen and it was paired with 🐘 Elephant, type
'Elephant', not 'animal', 'creature', or 'grey elephant'."
```
---
#### Screen 5: ImmediateRecallScreen
**Purpose:** Test immediate memory with typed responses
**Components needed:**
- Cue image display (white box, centered)
- Text input field (below cue)
- Submit button
- Timer countdown (optional visual)
- "Time is up!" message overlay
- Trial counter
**Required files:**
- `components/screens/VPAM/ImmediateRecallScreen.jsx`
- `components/shared/VPAM/RecallInput.jsx`
- `hooks/vpam/useRecallScreen.js`
**Critical logic:**
```javascript
// For each trial:
1. Display cue image
2. Start 15-second timer
3. Show text input field
4. Listen for:
- Submit button click
- Enter key press
- Timer expiration
5. Validate response against correct answer
6. Record:
- Response text
- Reaction time (ms from cue to submit)
- Accuracy (1/0)
7. If timeout show "Time is up!" for 1s
8. Clear input and load next trial
9. After trial 35 transition to Delay Interval
```
**Response validation:**
```javascript
function validateResponse(userInput, correctAnswer) {
// Normalize both strings
const normalized = userInput.toLowerCase().trim();
const correct = correctAnswer.toLowerCase().trim();
// Exact match required
return normalized === correct;
// Optional: Allow minor typos (Levenshtein distance ≤ 1)
// But be careful - too lenient affects data validity
}
```
---
#### Screen 6: DelayIntervalScreen
**Purpose:** Transition message and launch filler tasks
**Components needed:**
- Transition message display
- Automatic task chaining
- Timer tracking (15 minutes total)
- Progress indicator (optional)
**Required files:**
- `components/screens/VPAM/DelayIntervalScreen.jsx`
- `hooks/vpam/useDelayInterval.js`
**Transition messages:**
Adolescents:
```
"Great job looking at all the pairs! Before we test your memory, you'll
play a few short brain-teaser games. These games are like a quick workout
for your mind. Once you're done, we'll bring you back to check how many
pairs you can remember!"
```
Adults:
```
"Well done—you've completed the first part. Next, you'll do a few short
thinking activities designed to keep your mind active while your memory
continues to work in the background. After that, we'll return to test how
well you remember the pairs."
```
**Filler task sequence:**
```javascript
// Import and chain existing components:
1. <ResponseInhibitionTest /> (Go/No-Go)
2. <CognitiveFlexibilityTest /> (CFT)
3. <StroopTest /> (Attention - if available)
// Track elapsed time
// At 15:00 → auto-launch Delayed Recall
```
---
#### Screen 7: DelayedRecallInstructionScreen
**Purpose:** Re-explain recall task after delay
**Components needed:**
- "Welcome back" message
- Reminder of task rules
- "Let's Go!" button
**Required files