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:
// Or stacked for mobile:
``` **Recall Phase:** ```javascript // Cue display:
// Input field: ``` **Recognition Phase:** ```javascript // Cue at top:
// Three options (horizontal):
{options.map(option => ( ))}
// Selected state: ``` --- ## πŸ“Š 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 (
First item
+
Second item
); } ``` ### 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 (
{/* Cue Image */}
Cue
{/* Timer Bar */}
{/* Input Form */}
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" />
{/* Timeout Message */} {showTimeout && (

Time is up!

)}
); } ``` ### 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 (
{/* Cue Image */}
Cue
{/* Timer Bar */}
{/* Options */}
{options.map((option) => ( 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'} `} > Option ))}
{/* Timeout Message */} {showTimeout && (

Too Late!

)}
); } ``` --- ## πŸ“Š 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. (Go/No-Go) 2. (CFT) 3. (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