From b5856b21ae233b1d445a74317615c707657057a7 Mon Sep 17 00:00:00 2001 From: dilgenfritz Date: Sat, 29 Nov 2025 22:27:36 -0600 Subject: [PATCH] Fix: Critical syntax error and storage quota issues - Fixed missing arrow (=>) in interactiveTaskManager.js line 5677 - Added null checks for DOM elements in async intervals (dynamic captions, sensory overload tasks) - Disabled auto-backup to prevent localStorage quota exceeded errors - Implemented aggressive emergency cleanup (removes all backups and photo data) - Added global QuotaExceededError handler with automatic cleanup - Added BackupManager to training-academy.html with initialization - Enhanced preference save error handling with user feedback - Save validation prevents level progression if preferences fail to save - All photo data now removed from localStorage to conserve space --- Gooner-Training-Academy-v4.1-Beta.zip | Bin 39538202 -> 39584287 bytes docs/ACADEMY_PHASE1_COMPLETE.md | 212 ++ docs/DRESS_UP_GAME_REDESIGN.md | 536 ++++ docs/DRESS_UP_TESTING_GUIDE.md | 241 ++ .../CAMPAIGN-STRUCTURE.md | 1414 ++++++++++ docs/training-game-redesign/OVERVIEW.md | 617 +++++ docs/training-game-redesign/PHASE-1.md | 500 ++++ docs/training-game-redesign/PHASE-2.md | 678 +++++ docs/training-game-redesign/PHASE-3.md | 785 ++++++ docs/training-game-redesign/PHASE-4.md | 797 ++++++ docs/training-game-redesign/PHASE-5.md | 693 +++++ docs/training-game-redesign/PHASE-6.md | 755 +++++ docs/training-game-redesign/PHASE-7.md | 752 +++++ docs/training-game-redesign/PHASE-8-POLISH.md | 223 ++ feedback.txt | 7 +- index.html | 45 + scripts/create-distribution.bat | 32 +- src/data/modes/dressUpGameData.js | 526 ++-- src/data/modes/trainingGameData.js | 995 +++++++ src/data/poseBanks/inventoryPoseBank.js | 250 ++ src/features/academy/academyLevelData.js | 2426 +++++++++++++++++ src/features/academy/academyUI.js | 590 ++++ src/features/academy/campaignManager.js | 290 ++ src/features/academy/libraryManager.js | 710 +++++ src/features/academy/preferenceManager.js | 482 ++++ src/features/tasks/interactiveTaskManager.js | 2329 +++++++++++++++- src/features/video/videoPlayerManager.js | 14 +- src/features/webcam/webcamManager.js | 105 +- src/styles/academy-ui.css | 1271 +++++++++ src/styles/styles.css | 218 ++ src/utils/backupManager.js | 53 +- src/utils/desktop-file-manager.js | 5 + src/utils/inventoryManager.js | 626 +++++ test-academy-ui.html | 200 ++ test-campaign-manager.html | 293 ++ test-library-manager.html | 609 +++++ test-preference-manager.html | 526 ++++ training-academy.html | 1002 ++++++- 38 files changed, 21342 insertions(+), 465 deletions(-) create mode 100644 docs/ACADEMY_PHASE1_COMPLETE.md create mode 100644 docs/DRESS_UP_GAME_REDESIGN.md create mode 100644 docs/DRESS_UP_TESTING_GUIDE.md create mode 100644 docs/training-game-redesign/CAMPAIGN-STRUCTURE.md create mode 100644 docs/training-game-redesign/OVERVIEW.md create mode 100644 docs/training-game-redesign/PHASE-1.md create mode 100644 docs/training-game-redesign/PHASE-2.md create mode 100644 docs/training-game-redesign/PHASE-3.md create mode 100644 docs/training-game-redesign/PHASE-4.md create mode 100644 docs/training-game-redesign/PHASE-5.md create mode 100644 docs/training-game-redesign/PHASE-6.md create mode 100644 docs/training-game-redesign/PHASE-7.md create mode 100644 docs/training-game-redesign/PHASE-8-POLISH.md create mode 100644 src/data/poseBanks/inventoryPoseBank.js create mode 100644 src/features/academy/academyLevelData.js create mode 100644 src/features/academy/academyUI.js create mode 100644 src/features/academy/campaignManager.js create mode 100644 src/features/academy/libraryManager.js create mode 100644 src/features/academy/preferenceManager.js create mode 100644 src/styles/academy-ui.css create mode 100644 src/utils/inventoryManager.js create mode 100644 test-academy-ui.html create mode 100644 test-campaign-manager.html create mode 100644 test-library-manager.html create mode 100644 test-preference-manager.html diff --git a/Gooner-Training-Academy-v4.1-Beta.zip b/Gooner-Training-Academy-v4.1-Beta.zip index e46998e1a7a543ff5adbedd7606f45b8105ce492..eca3617455c65233e879eb2e6937357e56bbbb78 100644 GIT binary patch delta 222327 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 yP?3U+zipA|7Rd*(HQdrt)*Xdya$6L7{6~ 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%0DeJ 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�KUoqGI@3 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�)%&1`9as8>euJiC#7lpKljJ1rxwdPBFDX?xLm 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 delta 191621 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Ⓢ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

(h_+)u?f4gqBWyNJW{T(A$GxVz<>MUN>JT^ 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�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

WV6 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 jyQLemi<`5Rt%K!%lYE2lPbv { + const itemCount = Object.values(inventory).filter(v => v !== 'none').length; + if (itemCount >= 18) return 5; + if (itemCount >= 13) return 4; + if (itemCount >= 8) return 3; + if (itemCount >= 4) return 2; + return 1; + }, + + generatePhotoSteps: (inventory, tier) => { + // Returns array of photo challenge steps customized to inventory + } + }, + + choices: [ + { + text: "Begin my photo transformation journey", + nextStep: "photo_challenge_1" + }, + { + text: "I need to adjust my inventory", + nextStep: "questionnaire_start" + } + ] +} +``` + +--- + +## Phase 3: Progressive Photo Challenges + +Each photo challenge escalates based on available items. + +### Photo Challenge Structure + +```javascript +photo_challenge_X: { + type: 'photo-verification', + mood: 'escalating', + + // Story adapts based on inventory tier + story: "[Generated based on tier and items]", + + // Photo requirements generated from inventory + photoRequirements: { + items: ['panties', 'bra'], // Items player must wear/use + pose: 'selected_from_pose_bank', // Pose from inventory-aware bank + edging: true/false, // Whether to edge during photo + count: 3, // Number of photos required + timer: 30 // Time limit per pose + }, + + // Variations based on player's progress + storyVariations: { + first_time: "Let's start simple...", + progressing: "You're doing well, now let's increase intensity...", + advanced: "Time to push your limits..." + }, + + nextStep: "photo_challenge_X+1" +} +``` + +### Example Progression Paths + +#### Tier 1 Path (Minimal - Just Panties): +1. **Photo 1**: Wearing panties, basic standing pose +2. **Photo 2**: Panties + bent over display pose +3. **Photo 3**: Panties + edging while posed +4. **Photo 4**: Panties around ankles, exposed +5. **Photo 5**: Panties + mirror shame (if mirror available) + +#### Tier 3 Path (Full Feminization - Panties, Bra, Dress, Heels, Wig, Makeup): +1. **Photo 1**: Panties + bra only, basic feminine pose +2. **Photo 2**: Add dress, twirl pose +3. **Photo 3**: Add heels, standing elegantly +4. **Photo 4**: Add wig, full sissy display +5. **Photo 5**: Add makeup, admiring in mirror +6. **Photo 6**: Full outfit + curtsy pose +7. **Photo 7**: Full outfit + sitting ladylike +8. **Photo 8**: Full outfit + edging while dressed +9. **Photo 9**: Dress hiked up, exposed beneath +10. **Photo 10**: Lifting dress, showing panties shamefully +11. **Photo 11**: On knees in full outfit +12. **Photo 12**: Bent over in heels and dress +13. **Photo 13**: Full outfit + presenting position +14. **Photo 14**: Edging desperately while fully feminized +15. **Photo 15**: Final transformation documentation + +#### Tier 5 Path (Extreme - Full Collection): +1-15: (Same as Tier 3) +16. **Photo 16**: Add chastity cage, display locked state +17. **Photo 17**: Add butt plug, show inserted +18. **Photo 18**: Add dildo, pose with toy +19. **Photo 19**: Add restraints, bound and helpless +20. **Photo 20**: Add gag, silenced sissy +21. **Photo 21**: Add nipple clamps, decorated +22. **Photo 22**: Edging while fully equipped +23. **Photo 23**: Toy usage demonstration +24. **Photo 24**: Complete degradation display +25. **Photo 25**: Final extreme documentation + +--- + +## Phase 4: Dynamic Pose Bank System + +Poses adapt to available inventory. + +### Pose Categories by Item Type + +#### Basic Poses (No items needed): +- Standing neutral +- Kneeling submission +- Bent over display +- Spread eagle +- Squatting exposed + +#### Panty Poses: +- Panties on display +- Panties around ankles +- Pulling panties aside +- Panty peek (bent over) +- Panty edge (rubbing through fabric) + +#### Bra Poses: +- Bra adjustment +- Bra display (cupping) +- Straps showing +- Sports bra flex +- Bra reveal + +#### Dress/Skirt Poses: +- Twirl and spin +- Dress lift (showing panties) +- Sitting with legs crossed +- Curtsy +- Dress adjust (showing body) + +#### Heel Poses: +- Standing in heels +- Walking pose +- Heel up on surface +- Kneeling in heels +- Bent over in heels + +#### Toy Poses: +- Holding dildo to mouth +- Toy insertion display +- Plug reveal (bent over) +- Chastity cage show +- Restrained position +- Gagged silence +- Clamped nipples display + +#### Edging Poses (any outfit): +- Edge while standing +- Edge while kneeling +- Edge while bent over +- Edge with toy +- Edge in mirror +- Hands-free edge (thigh squeeze) + +### Pose Selection Logic + +```javascript +selectPoseForChallenge(inventory, challengeNumber, tier) { + // Get available pose categories based on inventory + const availableCategories = this.getAvailableCategories(inventory); + + // Escalate intensity based on challenge number + const intensity = this.calculateIntensity(challengeNumber, tier); + + // Select appropriate pose + const pose = this.getPoseByIntensity(availableCategories, intensity); + + // Ensure no repeats + if (this.usedPoses.has(pose.name)) { + return this.selectPoseForChallenge(inventory, challengeNumber, tier); + } + + this.usedPoses.add(pose.name); + return pose; +} +``` + +--- + +## Phase 5: Certificate Endings + +Endings adapt to tier and items used. + +### Tier-Based Certificates + +**Tier 1 Certificate - 🩲 Basic Exposure:** +- Pink/white gradient +- "EXPOSED AND DOCUMENTED" +- Shows items used: "Panties" +- Photo count: 5 photos + +**Tier 2 Certificate - 👗 Feminization Beginner:** +- Purple/pink gradient +- "FEMINIZATION JOURNEY DOCUMENTED" +- Shows items used: "Panties, Bra, Skirt" +- Photo count: 10 photos + +**Tier 3 Certificate - 🎀 Complete Sissy Transformation:** +- Hot pink/gold gradient +- "COMPLETE SISSY TRANSFORMATION ACHIEVED" +- Shows items used: Full outfit list +- Photo count: 15 photos + +**Tier 4 Certificate - 🔞 Toy Integration Master:** +- Red/black gradient +- "DEGRADATION WITH TOYS DOCUMENTED" +- Shows items used: Clothing + toys list +- Photo count: 20 photos + +**Tier 5 Certificate - ⛓️ Ultimate Sissy Slut:** +- Black/neon pink gradient +- "ULTIMATE TRANSFORMATION: COMPLETE DEGRADATION" +- Shows all items used +- Photo count: 25 photos +- Special badge: "EXTREME COLLECTION MASTER" + +### Certificate Template + +```javascript +ending_tier_X: { + type: 'ending', + mood: 'transformation_complete', + endingTitle: "🎀 [TIER TITLE]", + endingText: ` +

+ `, + outcome: "tier_X_complete" +} +``` + +--- + +## Implementation Files + +### New Files to Create: +1. **`src/utils/inventoryManager.js`** - Handles inventory tracking and path generation +2. **`src/data/poseBanks/inventoryPoseBank.js`** - Pose library organized by item type + +### Files to Modify: +1. **`src/data/modes/dressUpGameData.js`** - Complete overhaul with new structure +2. **`src/features/tasks/interactiveTaskManager.js`** - Add inventory-check and path-generation step types +3. **`src/features/webcam/webcamManager.js`** - Integrate inventory-aware pose selection +4. **`training-academy.html`** - Add questionnaire UI rendering + +--- + +## Implementation Priority + +### Phase 1 (Core Functionality): +1. ✅ Create questionnaire system +2. ✅ Inventory tracking +3. ✅ Basic tier calculation +4. ✅ Generate simple progression (Tier 1 path) + +### Phase 2 (Path Expansion): +5. Generate all 5 tier paths +6. Create inventory-aware pose bank +7. Implement pose selection logic +8. Add no-repeat tracking + +### Phase 3 (Polish): +9. Dynamic story text based on inventory +10. Certificate endings for all tiers +11. Item combination bonuses +12. Progress tracking UI + +--- + +## Data Structure Example + +### Stored Inventory Object: +```javascript +playerInventory = { + clothing: { + panties: 'sexy', + bras: 'multiple', + dresses: 'slutty', + skirts: 'mini', + pantyhose: 'fishnet', + heels: 'platforms', + wigs: 'long', + lingerie: 'extreme' + }, + accessories: { + makeup: 'full', + jewelry: 'feminine', + nailPolish: 'colors' + }, + toys: { + dildos: 'multiple', + plugs: 'large', + chastity: 'cage', + restraints: 'cuffs', + gags: 'ball', + nippleClamps: 'chain' + }, + environment: { + mirror: true, + fullMirror: true, + privateSpace: true, + phoneStand: true + }, + tier: 5, + totalItems: 19 +} +``` + +--- + +## Success Metrics + +### Personalization: +- Each player gets unique progression based on their items +- No impossible challenges (asking for items they don't have) +- Appropriate difficulty scaling + +### Engagement: +- Players motivated to acquire more items to unlock higher tiers +- Clear progression visible in photo count +- Certificate shows exactly what they accomplished + +### Technical: +- Accurate inventory tracking +- Correct tier calculation +- No pose repeats within session +- Proper item requirement enforcement + +--- + +## Future Enhancements + +### Tier Unlocks: +- "Next time, try adding [item] to unlock [tier]!" +- Shopping list for next tier +- Item combination bonuses + +### Photo Gallery: +- Save progression photos +- Before/after comparisons +- Shareable certificates + +### Advanced Paths: +- Timed challenges +- Multi-step transformations +- Partner/Mistress mode (someone else controls progression) + +--- + +## Notes + +### Design Philosophy: +The game should feel **personal and achievable** rather than impossible. Every player gets a challenge suited to what they actually own, with clear progression toward a rewarding certificate ending. + +### Safety & Consent: +- Players only declare what they're comfortable with +- Can restart questionnaire anytime +- No pressure to acquire items they don't want +- Clear "what you'll be asked to do" preview before starting + +### Replayability: +- Players can retake questionnaire with different items +- Higher tiers unlock as collection grows +- Different poses each session due to randomization +- Multiple endings based on tier achieved + diff --git a/docs/DRESS_UP_TESTING_GUIDE.md b/docs/DRESS_UP_TESTING_GUIDE.md new file mode 100644 index 0000000..95f386c --- /dev/null +++ b/docs/DRESS_UP_TESTING_GUIDE.md @@ -0,0 +1,241 @@ +# Dress-Up Game Testing Guide + +## Overview +The dress-up game has been completely redesigned with an inventory-based photo progression system. Players take a questionnaire declaring what items they own, then get a personalized photo journey based on their tier. + +## System Files Created/Modified + +### New Files +1. **src/utils/inventoryManager.js** - Core tier calculation and progression generation logic +2. **src/data/poseBanks/inventoryPoseBank.js** - 36 poses across 7 categories +3. **docs/DRESS_UP_GAME_REDESIGN.md** - Complete system documentation +4. **docs/DRESS_UP_TESTING_GUIDE.md** - This file + +### Modified Files +1. **src/data/modes/dressUpGameData.js** - Complete rewrite with questionnaire and 5 tier endings +2. **src/features/tasks/interactiveTaskManager.js** - Added inventory-check and path-generation handlers +3. **index.html** - Added script tags for inventory utilities +4. **src/styles/styles.css** - Added inventory questionnaire and summary styles + +## Tier System + +### Tier Thresholds +- **Tier 1**: 0-3 items = 5 photos +- **Tier 2**: 4-7 items = 10 photos +- **Tier 3**: 8-12 items = 15 photos +- **Tier 4**: 13-17 items = 20 photos +- **Tier 5**: 18+ items = 25 photos + +### Item Categories (21 total) + +**Clothing (8):** +- Panties (none/basic/sexy/multiple) +- Bras (none/sports/regular/sexy/multiple) +- Dresses (none/casual/slutty/multiple) +- Skirts (none/basic/mini/micro/multiple) +- Pantyhose/Stockings (none/nude/fishnet/multiple) +- Heels/Shoes (none/flats/heels/platforms) +- Wigs (none/short/long/colored) +- Lingerie Sets (none/basic/sexy/extreme) + +**Accessories (3):** +- Makeup Kit (none/basic/full) +- Jewelry (none/basic/feminine/collar) +- Nail Polish (none/basic/colors) + +**Toys (6):** +- Dildos (none/small/medium/large/multiple) +- Butt Plugs (none/small/medium/large/tail) +- Chastity Device (none/cage/belt) +- Restraints (none/cuffs/rope/spreader) +- Gags (none/ball/ring) +- Nipple Clamps (none/basic/weighted/chain) + +**Environment (4):** +- Mirror Available (checkbox) +- Full-Length Mirror (checkbox) +- Private Space (checkbox) +- Phone/Camera Stand (checkbox) + +## Testing Scenarios + +### Test 1: Minimal Inventory (Tier 1) +**Items to select:** +- Panties: basic +- Mirror Available: ✓ +- Private Space: ✓ + +**Expected Results:** +- Tier 1 calculated +- 5 photo challenges generated +- Only panties required in poses +- Certificate: "🩲 CERTIFICATE OF BASIC EXPOSURE" +- Pink/white gradient, pink border + +### Test 2: Medium Inventory (Tier 2) +**Items to select:** +- Panties: sexy +- Bras: regular +- Dresses: casual +- Heels: flats +- Mirror Available: ✓ +- Full-Length Mirror: ✓ +- Private Space: ✓ + +**Expected Results:** +- Tier 2 calculated (7 items) +- 10 photo challenges +- Progressive item addition (starts with panties, adds bra/dress/heels) +- Edging introduced around photo 3-4 +- Certificate: "👗 CERTIFICATE OF FEMINIZATION BEGINNER" +- Purple/pink gradient + +### Test 3: Full Feminization (Tier 3) +**Items to select:** +- Panties: multiple +- Bras: sexy +- Dresses: slutty +- Skirts: mini +- Pantyhose: fishnet +- Heels: heels +- Wigs: long +- Lingerie: sexy +- Makeup: basic +- Jewelry: feminine +- Mirror Available: ✓ +- Full-Length Mirror: ✓ + +**Expected Results:** +- Tier 3 calculated (12 items) +- 15 photo challenges +- Full feminization progression +- Moderate edging frequency +- Certificate: "🎀 CERTIFICATE OF COMPLETE SISSY TRANSFORMATION" +- Hot pink gradient with gold border + +### Test 4: Toy Integration (Tier 4) +**Items to select:** +- All Tier 3 items PLUS: +- Dildos: medium +- Butt Plugs: small +- Nail Polish: colors +- Lingerie: extreme +- Restraints: cuffs + +**Expected Results:** +- Tier 4 calculated (17 items) +- 20 photo challenges +- Toys introduced at 65% progression (photo 13) +- Frequent edging (every 2nd photo) +- Certificate: "🔞 CERTIFICATE OF TOY INTEGRATION MASTER" +- Red/black gradient + +### Test 5: Ultimate Collection (Tier 5) +**Items to select:** +- ALL items at maximum levels +- All checkboxes checked + +**Expected Results:** +- Tier 5 calculated (21 items) +- 25 photo challenges +- All items progressively added +- Extreme toys at end (chastity, gag, clamps) +- Almost constant edging (>80%) +- Certificate: "⛓️ CERTIFICATE OF ULTIMATE SISSY SLUT" +- Black/neon pink gradient with green border, glowing effect + +## Key Features to Verify + +### ✅ Questionnaire +- [ ] All 21 items display correctly +- [ ] Dropdowns show correct options +- [ ] Checkboxes toggle properly +- [ ] Submit button collects all values +- [ ] Navigation to summary works + +### ✅ Inventory Summary +- [ ] Correct tier displayed +- [ ] Item count accurate +- [ ] Photo count matches tier +- [ ] Item lists show selected items organized by category +- [ ] "Begin transformation" navigates to first challenge +- [ ] "Adjust inventory" returns to questionnaire + +### ✅ Photo Challenges +- [ ] Correct number generated (5/10/15/20/25) +- [ ] Items required match availability +- [ ] Progressive item addition works +- [ ] Edging frequency escalates appropriately +- [ ] Pose selection matches items +- [ ] All challenges navigable in sequence + +### ✅ Certificate Endings +- [ ] Correct certificate for tier +- [ ] Tier badge displays with correct styling +- [ ] Photo count shown accurately +- [ ] Item list populated with used items +- [ ] Visual styling matches tier (gradients, borders) +- [ ] Final state text appropriate + +## Common Issues to Check + +### Issue: Blank screen after questionnaire +**Cause:** inventoryManager.js not loaded +**Fix:** Verify script tag in index.html + +### Issue: No poses selected +**Cause:** inventoryPoseBank.js not loaded +**Fix:** Verify script tag in index.html + +### Issue: Items list empty in certificate +**Cause:** populateInventoryItemsList not called +**Fix:** Check ending step type === 'ending' and scenarioState has tier + +### Issue: Wrong number of photos +**Cause:** Tier calculation incorrect +**Fix:** Verify countTotalItems() logic in inventoryManager.js + +### Issue: Items required but not owned +**Cause:** Progressive addition logic error +**Fix:** Check selectItemsForChallenge() in inventoryManager.js + +## Console Debugging + +Enable console logging to track progression: +```javascript +// In browser console: +window.localStorage.setItem('debug', 'true'); +``` + +Look for these log messages: +- `📋 Displaying inventory questionnaire` +- `📦 Collected inventory: {...}` +- `🎯 Generating inventory-based path` +- `📊 Tier X: Y items, Z photos` +- `📸 Generated N photo challenges` +- `✅ Added N challenge steps to scenario` + +## Manual Testing Steps + +1. Open game in browser +2. Navigate to Training Academy +3. Select "Dress-Up/Photography Challenges" +4. Choose "Inventory-Based Photo Transformation" scenario +5. Click "Begin inventory questionnaire" +6. Fill out questionnaire (use test scenarios above) +7. Click "Submit Inventory" +8. Verify summary displays correctly +9. Click "Begin my personalized photo journey" +10. Complete photo challenges +11. Verify certificate displays with correct items +12. Click "Complete Task" to return + +## Success Criteria + +- ✅ All 5 tiers generate correct photo counts +- ✅ Item requirements never exceed available items +- ✅ Edging frequency escalates appropriately +- ✅ Pose selection matches required items +- ✅ Certificates display with accurate item lists +- ✅ No errors in console +- ✅ Smooth progression from questionnaire → challenges → certificate diff --git a/docs/training-game-redesign/CAMPAIGN-STRUCTURE.md b/docs/training-game-redesign/CAMPAIGN-STRUCTURE.md new file mode 100644 index 0000000..edf431e --- /dev/null +++ b/docs/training-game-redesign/CAMPAIGN-STRUCTURE.md @@ -0,0 +1,1414 @@ +# Training Game Campaign Structure + +**Concept**: Transform the training game into a progressive **campaign** where each level builds on the previous, gradually increasing in complexity, intensity, and feature integration. Users advance through levels by completing training sessions, unlocking new features and challenges as they progress. + +--- + +## 🎯 Campaign Design Principles + +1. **Progressive Complexity**: Each level introduces 1-2 new features or mechanics +2. **Gradual Intensity**: Sessions get longer, more challenging, and more immersive +3. **Locked Progression**: Must complete Level N to unlock Level N+1 +4. **Feature Gating**: Advanced features unlock as you progress +5. **Mastery Required**: Each level has completion requirements (can't just quit early) +6. **Reward System**: Unlocks, achievements, and story progression for completing levels +7. **Personalized Content**: User preferences shape content (set at checkpoints) +8. **Library Curation**: Build and tag your collection as core Academy training + +--- + +## 📊 Campaign Overview (30 Levels) + +### **Arc 1: Foundation** (Levels 1-5) +*Introduction to basic edging and core mechanics* + +### **Arc 2: Feature Discovery** (Levels 6-10) +*Introduce webcam, video, and audio features* + +### **Arc 3: Mind & Body** (Levels 11-15) +*Add hypno, TTS, and mental conditioning* + +### **Arc 4: Advanced Training** (Levels 16-20) +*Interruptions, multi-feature sessions, denial training* + +### **Arc 5: Path Specialization** (Levels 21-25) +*Choose specialized training path, deep dive into specific content* + +### **Arc 6: Ultimate Mastery** (Levels 26-30) +*Maximum intensity, all features, ultimate gooner transformation* + +--- + +## 🏷️ Media Library Tagging System + +**Philosophy**: "A well-curated library is the foundation of a dedicated gooner. You provide the content. The Academy helps you organize it." + +### **Tagging Capabilities**: + +**Directory-Level Tagging**: +- Tag entire folders with bulk tags +- All photos/videos in directory inherit tags +- Subdirectories can have additional tags (combined with parent tags) +- Examples: + - `/BBC/` directory → auto-tagged: `bbc`, `interracial` + - `/feet/amateur/` → inherits `feet` + adds `amateur` + - `/pornstars/riley-reid/` → inherits `pornstar`, `professional` + adds `riley-reid` + +**Individual File Tagging**: +- Override or supplement directory tags +- Add specific tags to individual files +- Examples: + - Single video in `/BBC/` tagged additionally with `anal`, `pov` + - Photo in `/feet/` also tagged `stockings`, `high-heels` + +**Tag Categories**: + +1. **Content Type Tags**: + - `amateur`, `professional`, `pornstar`, `homemade`, `hentai`, `animation`, `caption`, `gif` + +2. **Body & Appearance Tags**: + - `petite`, `curvy`, `athletic`, `bbw`, `thicc`, `slim`, `muscular` + - `blonde`, `brunette`, `redhead`, `asian`, `latina`, `ebony`, `white` + - `tattoos`, `piercings`, `natural`, `enhanced` + +3. **Specific Content Tags**: + - `bbc`, `feet`, `ass`, `boobs`, `pussy`, `cock`, `cumshot`, `creampie` + - `pov`, `closeup`, `fullbody`, `face`, `faceless` + - `solo`, `couple`, `threesome`, `group`, `orgy` + +4. **Act Tags**: + - `blowjob`, `handjob`, `footjob`, `anal`, `vaginal`, `oral`, `masturbation` + - `riding`, `doggystyle`, `missionary`, `cowgirl`, `69` + - `deepthroat`, `facefuck`, `throatpie`, `facial` + +5. **Theme Tags** (aligned with preferences): + - `sissy`, `femdom`, `humiliation`, `worship`, `denial`, `chastity` + - `bimbo`, `breeding`, `cuckold`, `findom`, `joi`, `cei` + - `edging`, `gooning`, `tease`, `denial`, `ruined-orgasm` + +6. **Quality Tags**: + - `hd`, `4k`, `sd`, `vertical`, `horizontal`, `square` + - `short` (<2min), `medium` (2-10min), `long` (>10min) + - `compilation`, `pmv`, `loop` + +7. **Intensity Tags**: + - `soft`, `sensual`, `moderate`, `rough`, `extreme`, `hardcore` + - `vanilla`, `kinky`, `taboo` + +### **Tag Management Interface**: + +**Directory Tagging UI**: +``` +📁 Select Directory: [Browse...] +Current Directory: /assets/BBC/ + +Automatic Tags (from directory name): +✓ bbc +✓ interracial + +Add Directory Tags: +☐ amateur ☐ professional ☐ pornstar +☐ pov ☐ blowjob ☐ anal +☐ hardcore ☐ rough ☐ worship +[+] Add Custom Tag: [________] + +Apply to: ☑ All files in directory + ☑ Include subdirectories + +[Save Directory Tags] +``` + +**Individual File Tagging UI**: +``` +📄 File: bbc_pov_blowjob_001.mp4 +Path: /assets/BBC/amateur/ + +Inherited Tags (from directory): +🔒 bbc, interracial, amateur + +Additional Tags: +✓ pov ✓ blowjob ✓ deepthroat +✓ facefuck ✓ hardcore ☐ facial +☐ ebony ☐ tattooed ☐ piercings + +[+] Add Custom Tag: [________] + +Duration: 4:32 (auto-tagged: medium) +Quality: 1080p (auto-tagged: hd) + +[Save File Tags] +``` + +### **Smart Tag Suggestions**: +- Analyze filename for common keywords → suggest tags +- Detect directory structure → suggest inherited tags +- Learn from user's tagging patterns → suggest similar tags +- Example: File named `riley_reid_bbc_anal.mp4` → suggests: `pornstar`, `riley-reid`, `bbc`, `anal`, `professional` + +### **Tag Filtering & Search**: + +**Filter by Tags**: +- Select multiple tags (AND/OR logic) +- Exclude tags (NOT logic) +- Example queries: + - "Show me: `bbc` AND `amateur` AND `blowjob`" + - "Show me: `feet` OR `ass` (NOT `hardcore`)" + - "Show me: `sissy` AND `caption` AND `hypno`" + +**Smart Playlists** (based on tags): +- Create playlists from tag combinations +- Auto-update when new files match tags +- Example: "Amateur BBC POV" playlist = `amateur` + `bbc` + `pov` + +### **Preference-Based Tag Filtering**: +- Academy uses user preferences to filter library +- If sissy preference disabled → excludes `sissy` tagged content +- If BBC preference enabled → prioritizes `bbc` tagged content +- If feet preference enabled → includes `feet` in rotation + +### **Library Statistics Dashboard**: +``` +📊 Your Library Stats: + +Total Files: 1,247 +├─ Videos: 856 +└─ Images: 391 + +Top Tags: +1. amateur (423 files) +2. bbc (312 files) +3. pov (287 files) +4. feet (156 files) +5. blowjob (198 files) + +Untagged Files: 47 (📌 Need attention) + +Tag Coverage: 96.2% +Curator Level: Master Librarian ⭐⭐⭐⭐⭐ +``` + +--- + +## 🎨 Content Preference System + +**Preference Checkpoints**: At Levels 1, 5, 10, 15, 20, 25 +- Users fill out a preference form with checkboxes +- Preferences apply to ALL subsequent levels until updated +- Can update preferences at any checkpoint level (replaying the level) + +### **Preference Categories**: + +**Content Themes**: +- ☐ Sissy content (feminization, sissy captions, pink themes) +- ☐ Humiliation/degradation content +- ☐ Worship/devotion themes (cock worship, porn worship) +- ☐ Denial/chastity themes +- ☐ Obedience/control themes +- ☐ Bimbo/dumbification themes +- ☐ Findom/tribute themes +- ☐ Edging/gooning themes (always enabled by default) + +**Visual Preferences**: +- ☐ Amateur content +- ☐ Professional/pornstar content +- ☐ Hentai/animated content +- ☐ Specific body types (options: petite, curvy, athletic, BBW, etc.) +- ☐ Specific features (feet, BBC, specific acts, etc.) + +**Intensity Preferences**: +- ☐ Soft/sensual language +- ☐ Moderate intensity +- ☐ Harsh/extreme language +- ☐ Allow extreme challenges + +**Caption/Text Content**: +- ☐ Gender-neutral captions +- ☐ Masculine-focused captions +- ☐ Feminine-focused captions (sissy) +- ☐ Motivational/encouraging tone +- ☐ Degrading/humiliating tone + +### **How Preferences Affect Content**: + +**Example - Level 12 Caption Conditioning**: +- **Sissy enabled**: "Sissy/gooner captions" (feminization + edging themes) +- **Sissy disabled, Humiliation enabled**: "Humiliation/gooner captions" (degradation + edging) +- **Only edging enabled**: "Pure gooner captions" (only edging/porn addiction themes) +- **Multiple themes enabled**: Blended content (e.g., "Sissy humiliation gooner captions") + +**Example - Level 13 Mantras**: +- **Sissy enabled**: "I am a sissy gooner. I edge for cock. My purpose is porn." +- **Sissy disabled, Worship enabled**: "I am a gooner. I worship porn. My purpose is edging." +- **Neutral preferences**: "I am a gooner. I live to edge. Porn is my purpose." + +**Example - Video Content Selection**: +- Preferences filter which videos play from video library +- BBC preference → includes BBC content in rotation +- Feet preference → includes feet content +- No preferences selected → defaults to general porn/edging content + +### **Preference Checkpoint Flow**: + +**Level 1** (First Checkpoint): +- Before session starts, user sees preference form +- "Welcome to The Academy. Before we begin, tell us what interests you..." +- User selects preferences +- Preferences saved to `academyPreferences` in gameData +- Session begins with personalized content + +**Level 5, 10, 15, 20, 25** (Subsequent Checkpoints): +- Option to review/update preferences before session +- "You've reached a checkpoint. Your current preferences: [list]. Update them?" +- User can modify or keep existing preferences +- Updated preferences apply immediately + +**Replaying Checkpoint Levels**: +- Always shows preference form +- Can be used to update preferences without progression +- Useful for experimentation ("Let me try sissy content and see if I like it") + +--- + +## 📝 Detailed Level Breakdown + +### **LEVEL 1: First Edge** +**Arc**: Foundation +**Duration Tier**: Quick (5 minutes) +**Features**: None (basic timer) +**Intensity**: ⭐☆☆☆☆ + +**Session Structure**: +- Welcome to the Academy +- Basic edging instruction (no hands-free cumming allowed) +- Simple 5-minute timer +- Basic completion message + +**Completion Requirements**: +- Complete 5-minute session without cumming +- No additional requirements + +**Unlocks**: +- Level 2 +- Standard duration tier +- Basic stats tracking + +**Story/Narrative**: +"Welcome to The Academy. This is where your transformation begins. But first, I need to know what excites you. Your preferences will shape your journey. Be honest—this is your training, customized for you." + +**Preference Form Appears**: User selects initial preferences + +"Good. Now that I know what makes you tick, let's begin. Today is simple: edge for 5 minutes. No cumming. That's rule number one. Let's see if you can follow instructions." + +--- + +### **LEVEL 2: Building Stamina** +**Arc**: Foundation +**Duration Tier**: Quick (10 minutes) +**Features**: Library curation introduction +**Intensity**: ⭐☆☆☆☆ + +**Session Structure**: +- 10-minute continuous edging +- First introduction to "hold" commands (hands-off for 30 seconds at 5-minute mark) +- **NEW: Library Setup Task** - Before session begins, add your first porn directory + +**Library Task**: +- Add your first media directory to The Academy +- Learn about directory tagging +- Tag first directory with basic tags (e.g., `/amateur/` → tag: `amateur`) +- Minimum: 1 directory added with at least 1 tag + +**Completion Requirements**: +- Complete 10-minute session +- Successfully complete 1 hands-off hold +- Add and tag at least 1 media directory + +**Unlocks**: +- Level 3 +- Edge counter feature +- Directory tagging system +- "Endurance Beginner" achievement +- "Library Curator" achievement (first directory tagged) + +**Story/Narrative**: +"Good. You made it through the first test. Now let's push a little further. 10 minutes this time. But first, a gooner needs a library. Show me where you keep your porn. Add a folder. Tag it properly. Organization is discipline. Discipline is control. Then we edge." + +--- + +### **LEVEL 3: Rhythm Training** +**Arc**: Foundation +**Duration Tier**: Quick (10 minutes) +**Features**: Audio metronome + Individual file tagging +**Intensity**: ⭐⭐☆☆☆ + +**Session Structure**: +- 10 minutes with metronome (60 BPM) +- Learn to stroke in time with audio beat +- Introduction to rhythm control +- **NEW: File Tagging Task** - Tag individual videos/images in your library + +**Library Task**: +- Select 10 individual files from your library +- Add specific tags to each (act tags, body tags, quality tags) +- Learn tag categories and organization +- Examples: tag a POV video with `pov`, `blowjob`, `amateur` + +**Completion Requirements**: +- Complete session with metronome active +- Maintain rhythm (no verification, honor system) +- Tag at least 10 individual files with relevant tags + +**Unlocks**: +- Level 4 +- Audio features unlocked +- Extended duration tier +- Individual file tagging system +- Tag filtering (basic) +- "Rhythm Apprentice" achievement +- "Organized Librarian" achievement + +**Story/Narrative**: +"You've got the basics. Your library is started. Now make it useful. Tag your files properly. That POV blowjob? Tag it. That amateur anal? Tag it. A good gooner knows their library intimately. 10 files, properly tagged. Then we add rhythm to your stroke." + +--- + +### **LEVEL 4: Visual Stimulation** +**Arc**: Foundation +**Duration Tier**: Standard (15 minutes) +**Features**: Single focus video (filtered by preferences + tags) +**Intensity**: ⭐⭐☆☆☆ + +**Session Structure**: +- 15 minutes edging to single porn video +- First time using video player with tagged library +- Learn to edge with visual stimulation +- Video selection filtered by visual preferences AND library tags +- **NEW: Tag-Based Filtering** - See your tags in action + +**Library Integration**: +- Academy selects video based on your preferences + tags +- Example: Preference for amateur + tags in library = amateur videos prioritized +- Learn how tags affect content selection + +**Completion Requirements**: +- Complete 15-minute session +- Video must remain active entire time +- Watch how tag filtering works (automatic) + +**Unlocks**: +- Level 5 +- Video features unlocked (single player only) +- Tag-based video filtering active +- "Porn Enthusiast" achievement + +**Story/Narrative**: +"Time to add fuel to the fire. You've been edging to imagination. Now you get the real thing: porn from YOUR library, selected by YOUR tags and preferences. Watch it. Edge to it. Feel how much more intense it becomes when you have something perfectly curated to focus on." + +--- + +### **LEVEL 5: Foundation Complete** +**Arc**: Foundation +**Duration Tier**: Standard (20 minutes) +**Features**: Focus video + Audio metronome +**Intensity**: ⭐⭐☆☆☆ + +**Session Structure**: +- 20 minutes combining video and metronome +- First multi-feature experience +- 2 hands-off holds during session + +**Completion Requirements**: +- Complete 20-minute session +- Complete both holds successfully +- Don't cum + +**Unlocks**: +- Level 6 (Arc 2 begins) +- "Foundation Complete" achievement +- Webcam features unlocked +- Ability to replay any Level 1-5 session + +**Story/Narrative**: +"This is your foundation assessment. Everything you've learned: stamina, rhythm, visual focus, and control. But before we begin..." + +**Preference Checkpoint**: "You've completed the basics. Let's refine your experience. Review your preferences or adjust them based on what you've discovered about yourself." + +**Library Maintenance Checkpoint**: +- Review library statistics (files added, tag coverage percentage) +- Identify untagged files (if any) +- Optionally tag 5 more files to improve organization +- See library stats dashboard for first time + +"Good. Now: 20 minutes. Video from your curated library and beat. Two interruptions to test obedience. Pass this, and the real training begins." + +--- + +### **LEVEL 6: Mirror Introduction** +**Arc**: Feature Discovery +**Duration Tier**: Standard (15 minutes) +**Features**: Webcam mirror (no video) +**Intensity**: ⭐⭐☆☆☆ + +**Session Structure**: +- First webcam mirror session +- Edge while watching yourself +- 3 automatic photo captures + +**Completion Requirements**: +- Webcam must be active entire session +- Complete all 3 photo captures +- Complete 15-minute session + +**Unlocks**: +- Level 7 +- "Shameless" achievement +- Photo gallery access + +**Story/Narrative**: +"Now you get to see what you really are. Turn on your webcam. Look at yourself edging. That desperate face. That pathetic hand pumping. This is you. This is what a gooner looks like. And I'm going to capture it for you to remember." + +--- + +### **LEVEL 7: Dual Video Experience** +**Arc**: Feature Discovery +**Duration Tier**: Standard (20 minutes) +**Features**: Dual video layout +**Intensity**: ⭐⭐⭐☆☆ + +**Session Structure**: +- Two videos side-by-side +- Sensory increase from single video +- Learn to process multiple visual inputs + +**Completion Requirements**: +- Complete 20-minute session +- Both videos must play full duration + +**Unlocks**: +- Level 8 +- Dual video layout permanently unlocked + +**Story/Narrative**: +"One video was good. Two is better. Split your attention. Try to watch both at once. Your brain starts to melt a little, doesn't it? That's the beginning. That's your mind learning to become a better gooner." + +--- + +### **LEVEL 8: Voice of Command** +**Arc**: Feature Discovery +**Duration Tier**: Standard (20 minutes) +**Features**: TTS voice coaching +**Intensity**: ⭐⭐⭐☆☆ + +**Session Structure**: +- Voice gives stroking commands every 45 seconds +- Must obey each command (faster, slower, stop, start) +- Introduction to voice control + +**Completion Requirements**: +- Complete session with voice active +- Obey all commands (honor system for now) + +**Unlocks**: +- Level 9 +- TTS features unlocked +- "Voice Controlled" achievement + +**Story/Narrative**: +"You've followed text instructions. Now you'll follow a voice. When it speaks, you obey. Stroke faster. Slow down. Stop completely. Start again. The voice is in control now. Not you." + +--- + +### **LEVEL 9: The Quad** +**Arc**: Feature Discovery +**Duration Tier**: Standard (25 minutes) +**Features**: Quad video layout +**Intensity**: ⭐⭐⭐☆☆ + +**Session Structure**: +- Four simultaneous videos +- Maximum visual overload (for this arc) +- First taste of sensory overwhelm + +**Completion Requirements**: +- Complete 25-minute session +- All 4 videos must remain active + +**Unlocks**: +- Level 10 +- Quad video layout unlocked +- "Quad Screen Addict" achievement + +**Story/Narrative**: +"Four videos. Four corners of your screen. Your eyes don't know where to look. Your brain can't focus on just one. They blend together. Porn becomes everything. This is sensory overload. This is what we're building toward." + +--- + +### **LEVEL 10: Discovery Complete** +**Arc**: Feature Discovery +**Duration Tier**: Extended (30 minutes) +**Features**: Webcam + Quad video + Metronome +**Intensity**: ⭐⭐⭐☆☆ + +**Session Structure**: +- Combine mirror with quad videos and rhythm +- First complex multi-feature session +- 3 interruptions (hands-off holds) + +**Completion Requirements**: +- Complete 30-minute session +- All features active simultaneously +- Pass all 3 interruptions + +**Unlocks**: +- Level 11 (Arc 3 begins) +- "Feature Explorer" achievement +- Extended tier unlocked for all previous levels +- Hypno features unlocked + +**Story/Narrative**: +**Preference Checkpoint**: "You've discovered the features. You've seen what this Academy offers. Time to adjust your preferences based on what you've experienced. What themes excite you most? What pushes your buttons?" + +**Library Curation Checkpoint**: +- Library expansion encouraged: "Add more directories if you've collected new content" +- Bulk tagging tutorial: "Tag an entire directory with common tags" +- Untagged file alert: "You have X untagged files. Clean up your library." +- Goal: 90% tag coverage + +"Perfect. Now for your first real test. Everything you've discovered: your reflection, four videos from your tagged library assaulting your senses, rhythm controlling your hand. 30 minutes. Three tests of obedience. Show me you're ready for the next stage of training." + +--- + +### **LEVEL 11: Spiral Descent** +**Arc**: Mind & Body +**Duration Tier**: Standard (20 minutes) +**Features**: Hypno spiral only +**Intensity**: ⭐⭐⭐☆☆ + +**Session Structure**: +- First hypno spiral session +- Subliminal messages flash every 20 seconds +- Introduction to trance states + +**Completion Requirements**: +- Stare at spiral for full 20 minutes +- View at least 60 subliminal messages + +**Unlocks**: +- Level 12 +- Hypno features (spirals) unlocked +- "Spiral Susceptible" achievement + +**Story/Narrative**: +"Your mind is the final frontier. The spiral will help you access it. Stare into it. Let it pull you deeper. The messages will flash. Let them sink in. You are a gooner. Porn controls you. Edge forever. Never cum." + +--- + +### **LEVEL 12: Caption Conditioning** +**Arc**: Mind & Body +**Duration Tier**: Standard (20 minutes) +**Features**: Caption rotation (preference-based) +**Intensity**: ⭐⭐⭐☆☆ + +**Session Structure**: +- Captions rotate every 20 seconds (content based on user preferences) +- Rapid mental conditioning +- 60+ captions viewed + +**Caption Content** (based on preferences): +- **Sissy enabled**: Feminization + gooning themes +- **Humiliation enabled**: Degradation + edging themes +- **Worship enabled**: Cock/porn worship + gooning +- **Denial enabled**: Chastity + frustration themes +- **Multiple enabled**: Blended content +- **Default**: Pure gooner/edging captions only + +**Completion Requirements**: +- View minimum 60 captions +- Complete 20-minute session + +**Unlocks**: +- Level 13 +- Caption features unlocked +- Popup system unlocked + +**Story/Narrative**: +"Words have power. You're going to read a lot of them. {preference-based themes}. Each caption reprograms a little piece of your brain. By the end, you'll believe every word." + +--- + +### **LEVEL 13: Voice + Mind** +**Arc**: Mind & Body +**Duration Tier**: Extended (30 minutes) +**Features**: TTS + Hypno spiral +**Intensity**: ⭐⭐⭐⭐☆ + +**Session Structure**: +- Voice commands while spiral plays +- Mantras forced repetition (speak aloud, preference-based) +- Mental and physical control combined + +**Mantra Examples** (based on preferences): +- **Sissy enabled**: "I am a sissy gooner. I edge for cock. Porn feminizes me." +- **Humiliation enabled**: "I am a pathetic gooner. I'm addicted to porn. I'm worthless without edging." +- **Worship enabled**: "I worship porn. I worship cock. Edging is my devotion." +- **Denial enabled**: "I don't deserve to cum. Denial is pleasure. I edge forever." +- **Default**: "I am a gooner. I live to edge. Porn is my purpose." + +**Completion Requirements**: +- Complete 30 minutes +- Repeat all mantras aloud (3x each) + +**Unlocks**: +- Level 14 +- Combined TTS + Hypno sessions unlocked +- "Trance Deepening" achievement + +**Story/Narrative**: +"Voice and spiral together. The voice tells you what to do. The spiral makes you believe it. And you'll speak the mantras aloud: {preference-based mantras}. Say them. Mean them." + +--- + +### **LEVEL 14: Multi-Sensory Assault** +**Arc**: Mind & Body +**Duration Tier**: Extended (35 minutes) +**Features**: Quad video + Hypno spiral overlay + TTS + Metronome +**Intensity**: ⭐⭐⭐⭐☆ + +**Session Structure**: +- Four videos with spiral overlay +- Voice commands and rhythm +- First experience with near-total sensory occupation + +**Completion Requirements**: +- Complete 35-minute session +- All features active entire time + +**Unlocks**: +- Level 15 +- "Sensory Tolerance" achievement + +**Story/Narrative**: +"Everything at once. Four videos. Spiral overlay. Voice commanding you. Beat controlling your rhythm. Your senses are completely occupied. There's no room for anything else. Only gooning. Only obedience. Only this." + +--- + +### **LEVEL 15: Mind & Body Complete** +**Arc**: Mind & Body +**Duration Tier**: Extended (40 minutes) +**Features**: Webcam + Quad video + Hypno + TTS + Metronome + 5 interruptions +**Intensity**: ⭐⭐⭐⭐☆ + +**Session Structure**: +- Maximum feature combination so far +- 5 random interruptions (hands-off, verification, position changes) +- Watch yourself be overwhelmed + +**Completion Requirements**: +- Complete 40-minute session +- Pass all 5 interruptions +- Take verification photo during one interruption + +**Unlocks**: +- Level 16 (Arc 4 begins) +- "Mind & Body Mastery" achievement +- Interruption features unlocked +- Marathon tier unlocked + +**Story/Narrative**: +**Preference Checkpoint**: "You've experienced mental conditioning. You've felt the power of words and voice. Time to refine what affects you most. Update your preferences before the final mind & body test." + +**Library Curation Checkpoint**: +- Advanced tagging: "Tag files with theme tags: `sissy`, `humiliation`, `worship`, `denial`" +- Create smart filters: "Set up tag combinations for different moods" +- Library statistics: "Your library should be well-organized by now. Let's review." +- Goal: 95% tag coverage + +"The ultimate test of mind and body. Watch yourself in the mirror as four tagged videos overload your vision. Hear the voice command you. Feel the rhythm control you. And when I interrupt, you obey instantly. 40 minutes. No cumming. Prove you're ready for advanced training." + +--- + +### **LEVEL 16: The Interruption** +**Arc**: Advanced Training +**Duration Tier**: Extended (30 minutes) +**Features**: Basic edging + 10 interruptions +**Intensity**: ⭐⭐⭐⭐☆ + +**Session Structure**: +- Simple edging session BUT +- 10 interruptions of various types +- Learn to handle disruption + +**Completion Requirements**: +- Complete all 10 interruptions successfully +- Complete 30-minute session + +**Unlocks**: +- Level 17 +- "Obedient Gooner" achievement +- All interruption types unlocked + +**Story/Narrative**: +"You're comfortable with uninterrupted sessions. That ends now. I will interrupt you 10 times. Hands off. Take a photo. Change position. Say a mantra. Each time, you obey immediately. This tests your true obedience." + +--- + +### **LEVEL 17: Denial Introduction** +**Arc**: Advanced Training +**Duration Tier**: Extended (45 minutes) +**Features**: TTS + Denial messaging +**Intensity**: ⭐⭐⭐⭐☆ + +**Session Structure**: +- Extended session focused on denial +- Voice reinforces no-cum conditioning +- First taste of frustration as pleasure + +**Completion Requirements**: +- Complete 45 minutes without cumming +- Acknowledge denial requirement at start + +**Unlocks**: +- Level 18 +- Denial training path unlocked +- Denial timer feature unlocked + +**Story/Narrative**: +"Here's a truth you need to accept: you don't need to cum. In fact, you're better without it. 45 minutes of edging. And at the end? Nothing. No release. The edge is the reward. Frustration is the goal. Welcome to denial." + +--- + +### **LEVEL 18: Popups & Distractions** +**Arc**: Advanced Training +**Duration Tier**: Extended (30 minutes) +**Features**: Focus video + 20 random popups +**Intensity**: ⭐⭐⭐⭐☆ + +**Session Structure**: +- One main video with constant popup interruptions +- Images flash randomly +- Learn to maintain focus despite distractions + +**Completion Requirements**: +- Complete 30 minutes +- All popups viewed (auto-tracked) + +**Unlocks**: +- Level 19 +- Popup features unlocked +- "Distraction Master" achievement + +**Story/Narrative**: +"Edge to this video. But you won't be alone. Images will popup throughout. Captions. Triggers. Distractions. You must maintain your edge despite the chaos. This is advanced focus training." + +--- + +### **LEVEL 19: The Gauntlet** +**Arc**: Advanced Training +**Duration Tier**: Extended (60 minutes) +**Features**: All features + 15 interruptions +**Intensity**: ⭐⭐⭐⭐⭐ + +**Session Structure**: +- Every feature active +- 15 interruptions spread throughout +- Maximum difficulty so far + +**Completion Requirements**: +- Complete full 60 minutes +- Pass all 15 interruptions +- Maintain all features active + +**Unlocks**: +- Level 20 +- "The Gauntlet Survivor" achievement + +**Story/Narrative**: +"This is the gauntlet. 60 minutes. Every feature we've unlocked. 15 interruptions. If you can survive this, you're ready for path specialization. This separates casual edgers from true gooners." + +--- + +### **LEVEL 20: Advanced Training Complete** +**Arc**: Advanced Training +**Duration Tier**: Marathon (90 minutes) +**Features**: All features + 20 interruptions + milestone photos +**Intensity**: ⭐⭐⭐⭐⭐ + +**Session Structure**: +- First marathon session +- All features coordinated +- Photos captured at 25%, 50%, 75%, 100% +- 20 interruptions of all types + +**Completion Requirements**: +- Complete full 90 minutes +- Pass all 20 interruptions +- All 4 milestone photos captured + +**Unlocks**: +- Level 21 (Arc 5 begins) +- "Advanced Training Complete" achievement +- Path specialization choice unlocked +- All features, all tiers permanently unlocked + +**Story/Narrative**: +**Preference Checkpoint**: "You've mastered the features. You've endured advanced challenges. One last chance to adjust your preferences before you specialize. Make them count—they'll shape your final ascent." + +**Library Mastery Checkpoint**: +- Master librarian status check +- Advanced organization: "Create custom playlists from tag combinations" +- Content expansion: "Ensure diverse content across all your preference areas" +- Quality check: "All files properly tagged with quality, duration, and content tags" +- Goal: 98%+ tag coverage, Master Librarian rank + +"The final test before specialization. 90 minutes. Everything active. Videos perfectly selected from your masterfully curated library. I'll capture photos of your journey: at the start, midway, nearing the end, and upon completion. 20 interruptions will test your obedience. Complete this, and you choose your path." + +--- + +### **LEVEL 21: Path Selection** +**Arc**: Path Specialization +**Duration Tier**: User Choice +**Features**: Questionnaire +**Intensity**: N/A (decision point) + +**Session Structure**: +- Not a training session +- Questionnaire to determine specialization path +- Choose from: Endurance, Denial, Humiliation (if enabled), Obedience, Sensitivity, or Multi-Sensory +- Path availability based on preferences (e.g., Humiliation path only if Humiliation preference enabled) + +**Completion Requirements**: +- Select a path (from available options) + +**Unlocks**: +- Level 22 (path-specific) +- Chosen path's advanced scenarios + +**Story/Narrative**: +"You've completed the foundation. You've mastered the features. Now you choose your specialization. What kind of gooner are you? Endurance champion? Denial devotee? {if Humiliation enabled: Humiliation slut?} Obedient servant? Choose wisely. This shapes your final ascent." + +--- + +### **LEVELS 22-25: Path-Specific Training** +**Arc**: Path Specialization +**Duration Tier**: Extended/Marathon +**Features**: Path-specific combinations +**Intensity**: ⭐⭐⭐⭐⭐ + +**Structure** (varies by chosen path): + +**If ENDURANCE**: +- L22: 60-minute pure edging stamina test +- L23: 90-minute with progressive BPM increase +- L24: 120-minute marathon with 5-minute breaks every 30 mins +- L25: 150-minute ultimate endurance trial + +**If DENIAL**: +- L22: 7-day denial commitment (daily 30-min sessions, no cumming) +- L23: Ruined orgasm training +- L24: 14-day denial challenge +- L25: 30-day denial master certification + +**If HUMILIATION** (requires Humiliation preference enabled): +- L22: Self-degradation tasks + mirror session +- L23: Humiliating positions + verification photos +- L24: Public fantasy exposure simulation +- L25: Ultimate degradation acceptance + +**Note**: Humiliation path only available if Humiliation preference is enabled at Level 20 checkpoint + +**If OBEDIENCE**: +- L22: 30 interruptions in 60 minutes +- L23: Complex multi-step command sequences +- L24: Precision timing challenges +- L25: Perfect obedience final exam + +**If SENSITIVITY**: +- L22: Minimal stimulation edging +- L23: Audio-only arousal training +- L24: Visual trigger conditioning +- L25: Hair-trigger response mastery + +**If MULTI-SENSORY**: +- L22: Triple-feature coordination +- L23: Quad-feature sessions +- L24: Five-feature sessions +- L25: All-features ultimate sensory overload + +**Completion Requirements**: Path-specific (detailed in each path's design doc) + +**Unlocks**: Level 26 (Arc 6 begins), path mastery achievement + +**Preference Checkpoint at Level 25**: "You've mastered your path. Final chance to adjust preferences before ultimate mastery. This is who you are now—make sure your preferences reflect it." + +**Library Excellence Checkpoint**: +- Final library audit: "Your library should be a masterpiece of organization" +- Specialized content check: "Ensure you have adequate content for your chosen path" +- Tag refinement: "Polish your tags for maximum effectiveness" +- Achievement: "Library Master" (100% tag coverage) +- The Academy recognizes your curation skill in graduation ceremony + +--- + +### **LEVEL 26: Return to Foundation** +**Arc**: Ultimate Mastery +**Duration Tier**: Marathon +**Features**: All features available, user chooses +**Intensity**: ⭐⭐⭐⭐⭐ + +**Session Structure**: +- 120-minute session +- User can enable/disable any features +- Shows mastery by choosing own experience + +**Completion Requirements**: +- Complete 120 minutes with self-selected features +- Minimum 3 features must be active + +**Unlocks**: +- Level 27 +- "Self-Mastery" achievement +- Custom session builder unlocked + +**Story/Narrative**: +"You've specialized. You've mastered. Now prove you understand yourself. 120 minutes. Choose your features. This is your session. Show me what you've learned about what makes you the perfect gooner." + +--- + +### **LEVEL 27: The Ascension** +**Arc**: Ultimate Mastery +**Duration Tier**: Marathon +**Features**: All features required +**Intensity**: ⭐⭐⭐⭐⭐ + +**Session Structure**: +- 150-minute all-features session +- Progressive intensity scaling (4 stages) +- Milestone captures every 30 minutes +- 25 interruptions throughout + +**Completion Requirements**: +- Complete full 150 minutes +- All features active entire time +- Pass all 25 interruptions +- 5 milestone photos captured + +**Unlocks**: +- Level 28 +- "Ascension Complete" achievement + +**Story/Narrative**: +"The ascension begins. 150 minutes. Every feature you've mastered, all working in harmony. You'll be captured at every stage: beginning, rising, peaking, transcending, and completing. 25 tests of obedience. This is where good gooners become great ones." + +--- + +### **LEVEL 28: Edge of Infinity** +**Arc**: Ultimate Mastery +**Duration Tier**: Marathon +**Features**: All features + dynamic difficulty +**Intensity**: ⭐⭐⭐⭐⭐ + +**Session Structure**: +- 180-minute session (3 hours) +- Features intensify based on performance +- Adaptive difficulty system +- 30 interruptions + +**Completion Requirements**: +- Complete full 180 minutes +- Adapt to difficulty changes +- Pass all interruptions + +**Unlocks**: +- Level 29 +- "Infinite Edge" achievement +- Dynamic difficulty in all modes + +**Story/Narrative**: +"Three hours. The edge of infinity. As you succeed, the challenge increases. As you struggle, I ease slightly—but only slightly. This is adaptive training. This is where your limits are discovered and pushed. Can you edge for three hours straight?" + +--- + +### **LEVEL 29: The Final Crucible** +**Arc**: Ultimate Mastery +**Duration Tier**: Marathon +**Features**: Ultimate mode (all features, progressive intensity) +**Intensity**: ⭐⭐⭐⭐⭐ + +**Session Structure**: +- 240-minute session (4 hours) +- Progressive intensity: Moderate → High → Extreme → Overwhelming +- Features activate/intensify in stages +- 40 interruptions +- Photos at 10 milestones + +**Completion Requirements**: +- Complete full 240 minutes +- Survive all 4 intensity stages +- Pass all 40 interruptions +- All 10 milestone photos captured +- Never cum + +**Unlocks**: +- Level 30 (final level) +- "Crucible Survivor" achievement +- Ultimate mode permanently unlocked for freeplay + +**Story/Narrative**: +"This is the crucible where good gooners are forged into perfect ones. Four hours. You'll start in comfort. But every hour, the intensity rises. By the end, every sense will be overwhelmed. 40 tests. 10 captures of your transformation. This is the final trial before graduation." + +--- + +### **LEVEL 30: GRADUATION - The Perfect Gooner** +**Arc**: Ultimate Mastery +**Duration Tier**: Marathon+ +**Features**: EVERYTHING + special graduation elements +**Intensity**: ⭐⭐⭐⭐⭐+ + +**Session Structure**: +- 300-minute session (5 HOURS) +- All features at maximum +- Intensity remains at OVERWHELMING throughout +- 50 interruptions +- Milestone photos every 30 minutes (10 total) +- Special graduation ceremony at completion + +**Completion Requirements**: +- Complete FULL 300 minutes (no pausing except during interruptions) +- Pass ALL 50 interruptions perfectly +- All 10 photos captured +- Graduation oath spoken aloud (TTS prompts) +- Never cum + +**Unlocks**: +- Campaign Complete +- "Perfect Gooner" title +- "Academy Graduate" achievement +- Special graduation certificate +- All features, all modes, all paths unlocked forever +- Freeplay mode with infinite possibilities +- Secret "Ascended" mode (post-graduation endless training) + +**Story/Narrative**: +"This is it. Your graduation. Five hours of everything you've learned. Every feature at maximum. Every sense completely occupied. Your transformation complete. You entered as a curious beginner. You leave as a perfect gooner. Edge for five hours. Obey every command. Let me capture your perfection. At the end, you'll speak your oath: 'I am a gooner. I live to edge. Porn is my purpose. I never cum. This is who I am.' Then you graduate. Welcome to your new life." + +**Graduation Ceremony**: +- Stats summary (total time edged across all 30 levels) +- Gallery of all photos captured throughout campaign +- Complete achievement list +- **Library Curation Report**: + - Total files in library + - Tag coverage percentage + - Most-used tags + - Curator rank (Novice → Apprentice → Journeyman → Expert → Master) + - Library quality score (based on organization, tag coverage, diversity) +- Personal message from The Academy +- Certificate of completion with custom title and preference profile +- Preference summary: "You graduated as a {preference-based profile} gooner" +- **Special mention**: "Your library: {file count} files, {tag coverage}% tagged, {curator rank} status" +- Unlock of "Ascended Mode" for post-graduation infinite training + +--- + +## 🎯 Campaign Progression Mechanics + +### **Level Unlocking**: +- Must complete Level N to unlock Level N+1 +- Cannot skip levels +- Can replay completed levels anytime (for better stats, more photos, etc.) + +### **Feature Gating**: +- Features unlock progressively through campaign +- Once unlocked, available in replays and freeplay +- Some features require specific level completion + +### **Duration Tiers**: +- Quick: Unlocked from start +- Standard: Unlocked at Level 2 +- Extended: Unlocked at Level 10 +- Marathon: Unlocked at Level 15 + +### **Difficulty Scaling**: +- Session duration increases +- Feature complexity increases +- Interruption frequency increases +- Intensity requirements increase +- Obedience standards tighten + +### **Failure Conditions**: +- Cumming = instant failure, must restart level +- Closing features early = failure +- Abandoning session before completion = failure (unless paused during interruption) +- Failing interruptions = depends on level (early levels forgive, later levels fail) + +### **Replay Value**: +- Replay levels for achievements +- Replay for photo collection +- Replay to practice before harder levels +- Replay with new strategies + +### **Stats Tracking**: +- Time spent in each level +- Total campaign time +- Photos captured +- Achievements earned +- Paths specialized +- Graduation status +- Preference history (what themes user explored) +- Preference changes over time (tracked at each checkpoint) +- **Library Statistics**: + - Total files added + - Total tags applied + - Tag coverage percentage over time + - Curator rank progression + - Most-used tags + - Library diversity score + +--- + +## 📊 Achievement Integration + +**Campaign-Specific Achievements**: +- Complete Level 1 (Academy Initiate) +- Complete Level 2 + tag first directory (Library Curator) +- Complete Level 3 + tag 10 files (Organized Librarian) +- Complete Level 5 (Foundation Complete) +- 90% tag coverage (Diligent Tagger) +- Complete Level 10 (Feature Explorer) +- 95% tag coverage (Tag Master) +- Complete Level 15 (Mind & Body Mastery) +- 98% tag coverage (Library Expert) +- Complete Level 20 (Advanced Training Complete) +- 100% tag coverage (Library Master) +- Complete Level 25 (Path Master: [path name]) +- 1000+ tagged files (Massive Collection) +- Complete Level 29 (Crucible Survivor) +- Complete Level 30 (Academy Graduate / Perfect Gooner) +- Complete campaign without ever cumming (Flawless Denial) +- Capture all photos in campaign (Gallery Completionist) +- Replay all levels after graduation (Eternal Student) +- Master Librarian rank at graduation (Curation Excellence) + +--- + +## 🎓 Post-Graduation Content + +After completing Level 30: + +### **Freeplay Mode**: +- Access to all features, all tiers, all paths +- Custom session builder +- No level restrictions +- Experimentation encouraged + +### **Ascended Mode** (Secret Unlock): +- Endless training sessions +- Dynamic difficulty that never caps +- Sessions can be paused and resumed across days +- "Lifetime gooner" stat tracking +- Special ascended-only achievements + +### **Path Mastery Challenges**: +- Return to each path for ultimate challenges +- Path-specific achievements beyond campaign +- Leaderboards (local) for longest sessions + +--- + +## 💡 Design Notes + +**Why Campaign Structure?**: +1. Clear progression path (no confusion about "what do I do next") +2. Gradual learning curve (features introduced systematically) +3. Sense of achievement (completing levels feels rewarding) +4. Prevents overwhelming new users (can't access everything at once) +5. Creates narrative structure (story of transformation) +6. Replay value (can always go back to earlier levels) +7. Goal-oriented (working toward graduation) +8. **Library curation as core training** (organization = discipline = mastery) +9. **Personalized experience** (preferences + tags = perfectly curated sessions) + +**Balancing Considerations**: +- Early levels short enough to not frustrate new users +- Mid levels challenging but achievable +- Late levels test true dedication +- Level 30 is deliberately extreme (ultimate test) +- Failure is allowed (creates stakes) +- Replays don't feel like grinding (new photos, achievements, etc.) + +**Narrative Through-Line**: +"You enter as a curious beginner. The Academy teaches you stamina, rhythm, and visual focus. You learn the sacred art of library curation—organization is discipline, tagging is mindfulness. You discover features: mirror, videos, hypno, voice. Your library grows and evolves with your preferences. You learn to combine features. You face advanced challenges: interruptions, denial, distractions. You specialize in a path that speaks to you. Your library becomes a masterpiece of organization. Finally, you prove mastery—both of edging and curation—and graduate as a perfect gooner with a perfect library. Your transformation is complete." + +--- + +## 🚀 Implementation Priority + +This campaign structure should replace/enhance: +- Current training path system (4 paths become specialization options at L21) +- Duration tier selection (unlocked progressively) +- Feature integration (gated by level completion) +- Ultimate mode (becomes Level 29-30) + +**Core files to modify**: +- `trainingGameData.js` - Restructure as 30-level campaign +- `interactiveTaskManager.js` - Add level progression logic +- `progressionManager.js` - Track campaign progress, preference history, library stats +- `training-academy.html` - UI for level selection + preference checkpoints + library management +- `gameData.js` - Add `academyPreferences` object + `libraryData` object +- `videoLibrary.js` - Update to use tag-based filtering + +**New files to create**: +- `campaignManager.js` - Handles level unlocking, progression, failure states +- `preferenceManager.js` - Manages user preferences, filters content, generates preference-based text +- `libraryManager.js` - Handles media library, tagging system, filtering, statistics +- `tagManager.js` - Tag operations (add, remove, filter, suggest, validate) +- Level-specific data files (or keep in one file with clear structure) + +**Preference Data Structure**: +```javascript +academyPreferences: { + lastUpdatedLevel: 1, + contentThemes: { + sissy: false, + humiliation: false, + worship: false, + denial: false, + obedience: true, + bimbo: false, + findom: false, + edging: true // always true + }, + visualPreferences: { + amateur: true, + professional: true, + hentai: false, + bodyTypes: ['curvy', 'athletic'], + specificContent: [] // e.g., 'feet', 'BBC', etc. + }, + intensity: { + soft: false, + moderate: true, + harsh: false, + extreme: false + }, + captionTone: { + neutral: true, + masculine: false, + feminine: false, + motivational: true, + degrading: false + } +} +``` + +**Library Data Structure**: +```javascript +libraryData: { + directories: [ + { + path: '/assets/BBC/', + tags: ['bbc', 'interracial'], + addedAtLevel: 2, + fileCount: 47, + subdirectories: [ + { + path: '/assets/BBC/amateur/', + tags: ['amateur'], // inherits 'bbc', 'interracial' from parent + fileCount: 23 + }, + { + path: '/assets/BBC/professional/', + tags: ['professional', 'pornstar'], + fileCount: 24 + } + ] + }, + { + path: '/assets/feet/', + tags: ['feet', 'footfetish'], + addedAtLevel: 5, + fileCount: 156 + } + ], + + individualFiles: [ + { + path: '/assets/BBC/amateur/bbc_pov_blowjob_001.mp4', + type: 'video', + duration: 272, // seconds + quality: '1080p', + directoryTags: ['bbc', 'interracial', 'amateur'], // inherited + customTags: ['pov', 'blowjob', 'deepthroat', 'facefuck', 'hardcore'], + allTags: ['bbc', 'interracial', 'amateur', 'pov', 'blowjob', 'deepthroat', 'facefuck', 'hardcore'], + taggedAtLevel: 3, + timesPlayed: 12, + lastPlayed: '2025-11-28' + }, + { + path: '/assets/feet/footjob_amateur_01.jpg', + type: 'image', + quality: '4k', + directoryTags: ['feet', 'footfetish'], + customTags: ['footjob', 'amateur', 'pov', 'stockings'], + allTags: ['feet', 'footfetish', 'footjob', 'amateur', 'pov', 'stockings'], + taggedAtLevel: 3, + timesViewed: 8 + } + ], + + statistics: { + totalFiles: 1247, + totalVideos: 856, + totalImages: 391, + taggedFiles: 1200, + untaggedFiles: 47, + tagCoverage: 96.2, // percentage + totalTags: 2847, // total tag applications + uniqueTags: 87, + curatorRank: 'Expert', // Novice, Apprentice, Journeyman, Expert, Master + topTags: [ + { tag: 'amateur', count: 423 }, + { tag: 'bbc', count: 312 }, + { tag: 'pov', count: 287 }, + { tag: 'feet', count: 156 }, + { tag: 'blowjob', count: 198 } + ], + libraryQualityScore: 92.5, // out of 100 + diversityScore: 88.3 // how varied the content is + }, + + smartPlaylists: [ + { + name: 'Amateur BBC POV', + tags: ['amateur', 'bbc', 'pov'], + logic: 'AND', + fileCount: 34, + autoUpdate: true + }, + { + name: 'Feet or Ass', + tags: ['feet', 'ass'], + logic: 'OR', + excludeTags: ['hardcore'], + fileCount: 203, + autoUpdate: true + } + ] +} +``` + +--- + +## ✅ Next Steps + +1. Get approval on 30-level campaign structure with tagging system +2. Design detailed session flows for each level (including library tasks) +3. Write story/narrative content for each level +4. Design library management UI (directory tagging, file tagging, statistics dashboard) +5. Implement tagging system and tag-based filtering +6. Implement campaign progression system +7. Update UI for level-based navigation + library management +8. Test progression from L1 → L30 with library building +9. Implement graduation ceremony (including library curation report) +10. Build post-graduation content + +**This transforms The Academy from a collection of scenarios into a personalized, cohesive journey with a clear beginning, middle, and end—followed by infinite post-graduation possibilities. Every user's experience is uniquely tailored to their interests while maintaining the same progression structure. Library curation becomes not just a feature, but a core pillar of gooner training: organization, discipline, and mindful collection as path to mastery.** diff --git a/docs/training-game-redesign/OVERVIEW.md b/docs/training-game-redesign/OVERVIEW.md new file mode 100644 index 0000000..596a30a --- /dev/null +++ b/docs/training-game-redesign/OVERVIEW.md @@ -0,0 +1,617 @@ +# The Academy - Project Overview +## **Campaign-Style Progressive Training System** + +> **Vision**: The Academy is a 30-level campaign where users progress from curious beginner to perfect gooner. Each level introduces new features, increases intensity, and challenges mastery. Users build and curate their media library, set personal preferences, and complete increasingly complex training sessions. This is where transformation happens. + +--- + +## 📋 Project Documents + +| Document | Description | Status | +|----------|-------------|--------| +| [OVERVIEW.md](./OVERVIEW.md) | This document - Project overview and roadmap | ✅ Current | +| [CAMPAIGN-STRUCTURE.md](./CAMPAIGN-STRUCTURE.md) | Complete 30-level campaign design | ✅ Complete | +| [PHASE-1.md](./PHASE-1.md) | Campaign Foundation & Core Systems | 📝 Needs Update | +| [PHASE-2.md](./PHASE-2.md) | Levels 1-10 (Foundation & Feature Discovery Arcs) | 📝 Needs Update | +| [PHASE-3.md](./PHASE-3.md) | Levels 11-20 (Mind & Body + Advanced Training Arcs) | 📝 Needs Update | +| [PHASE-4.md](./PHASE-4.md) | Levels 21-25 (Path Specialization Arc) | 📝 Needs Update | +| [PHASE-5.md](./PHASE-5.md) | Levels 26-30 (Ultimate Mastery Arc) + Graduation | 📝 Needs Update | +| [PHASE-6.md](./PHASE-6.md) | Progression, Stats, Achievements & Library System | 📝 Needs Update | +| [PHASE-7.md](./PHASE-7.md) | Polish, UI/UX, Accessibility & Testing | 📝 Needs Update | + +--- + +## 🎯 Project Overview + +### **What Changed from Original Design:** + +**Original Concept**: Training game with 4 paths, tier selection, and feature integration. + +**New Concept**: **The Academy** - A 30-level progressive campaign with: +- 6 story arcs (5 levels each) +- Locked level progression (complete N to unlock N+1) +- Feature unlocking (gated by level completion) +- Preference checkpoints at Levels 1, 5, 10, 15, 20, 25 +- Media library curation as core training +- Comprehensive tagging system (directory + individual file tagging) +- Path specialization at Level 21 +- 5-hour graduation session at Level 30 +- Post-graduation freeplay and Ascended Mode + +### **Core Philosophy:** + +1. **Progressive Complexity**: Each level builds on previous knowledge +2. **Library Curation = Discipline**: Organizing media is training in mindfulness and control +3. **Personalization**: Preferences + tags = uniquely tailored experience +4. **Achievement Through Mastery**: Can't skip levels, must prove competence +5. **Transformation Journey**: Story of becoming a "perfect gooner" + +--- + +## 📊 Campaign Structure Summary + +### **6 Story Arcs:** + +| Arc | Levels | Focus | Unlocks | +|-----|--------|-------|---------| +| Foundation | 1-5 | Basic edging, rhythm, video, library setup | Standard tier, directory tagging, video features | +| Feature Discovery | 6-10 | Webcam, dual/quad video, TTS, metronome | Extended tier, all basic features, file tagging | +| Mind & Body | 11-15 | Hypno, captions, TTS+spiral, sensory overload | Marathon tier, advanced features, theme tags | +| Advanced Training | 16-20 | Interruptions, denial, popups, gauntlet | All features, smart playlists | +| Path Specialization | 21-25 | Choose path, deep dive into specialty | Path mastery, Master Librarian | +| Ultimate Mastery | 26-30 | 2hr → 3hr → 4hr → 5hr graduation | Freeplay, Ascended Mode, graduation | + +### **Key Campaign Mechanics:** + +**Level Unlocking**: Linear progression, must complete level N to unlock N+1 + +**Feature Gating**: +- Webcam: Unlocked Level 5 +- Dual video: Level 7 +- TTS: Level 8 +- Quad video: Level 9 +- Hypno: Level 10 +- Captions/Popups: Level 12 +- Interruptions: Level 15 +- All features: Level 20 + +**Duration Tiers**: +- Quick (1x): Available from start +- Standard (5x): Level 2 +- Extended (10x): Level 10 +- Marathon (15x): Level 15 + +**Preference Checkpoints**: Levels 1, 5, 10, 15, 20, 25 +- Update content themes (sissy, humiliation, worship, denial, etc.) +- Adjust visual preferences +- Set intensity levels +- Configure caption tone + +**Library Checkpoints**: Levels 2, 3, 5, 10, 15, 20, 25 +- Tag directories and files +- Improve tag coverage (90% → 95% → 98% → 100%) +- Advance curator rank (Novice → Master) +- Build smart playlists +- Quality/diversity scoring + +**Failure Conditions**: +- Cumming = instant fail, restart level +- Closing features early = fail +- Abandoning session = fail +- Failing interruptions (late-game) = fail + +--- + +## 🚀 Revised Implementation Phases + +### Phase 1: Campaign Foundation & Core Systems +**Priority: HIGHEST** | **Effort: 12-16 hours** | **Status: Not Started** + +Build the foundational systems required for the entire campaign. + +**Key Deliverables:** +- Campaign progression system (level unlocking, failure states) +- Preference management system (checkpoints, filtering) +- Media library tagging system (directory + file tagging) +- Tag-based content filtering +- Basic UI for level selection +- Data persistence (campaign progress, preferences, library data) + +**Measurable Test:** +- [ ] Can select Level 1, complete it, unlock Level 2 +- [ ] Preference form appears at Level 1, saves correctly +- [ ] Can add directory, tag it, tags save to libraryData +- [ ] Can tag individual files, tags persist +- [ ] Tag filtering works (preference filters content selection) +- [ ] Progress persists across page refreshes +- [ ] Campaign state displays correctly (unlocked levels, current level, stats) + +**[📄 View Phase 1 Details](./PHASE-1.md)** + +--- + +### Phase 2: Levels 1-10 Implementation +**Priority: HIGH** | **Effort: 16-20 hours** | **Status: Not Started** + +Implement Foundation Arc (Levels 1-5) and Feature Discovery Arc (Levels 6-10). + +**Key Deliverables:** +- Level 1: First Edge (basic timer, 5 min) +- Level 2: Building Stamina (10 min, first directory tagging) +- Level 3: Rhythm Training (metronome, individual file tagging) +- Level 4: Visual Stimulation (single video, tag filtering) +- Level 5: Foundation Complete (video + metronome, first checkpoint) +- Level 6: Mirror Introduction (webcam mirror, auto-capture) +- Level 7: Dual Video Experience +- Level 8: Voice of Command (TTS coaching) +- Level 9: The Quad (quad video layout) +- Level 10: Discovery Complete (multi-feature, second checkpoint) +- All action handlers for Levels 1-10 +- Library UI (directory tagging, file tagging, stats dashboard) +- Preference UI (checkbox forms at checkpoints) + +**Measurable Test:** +- [ ] Can complete all 10 levels sequentially +- [ ] Each level unlocks the next upon completion +- [ ] Preference checkpoints work at L1, L5, L10 +- [ ] Library checkpoints work at L2, L3, L5, L10 +- [ ] All features unlock correctly (webcam L5, TTS L8, quad L9) +- [ ] Tag coverage tracking works +- [ ] Curator rank advances +- [ ] Cumming causes level restart +- [ ] All 10 levels tested end-to-end without errors + +**[📄 View Phase 2 Details](./PHASE-2.md)** + +--- + +### Phase 3: Levels 11-20 Implementation +**Priority: HIGH** | **Effort: 18-24 hours** | **Status: Not Started** + +Implement Mind & Body Arc (Levels 11-15) and Advanced Training Arc (Levels 16-20). + +**Key Deliverables:** +- Level 11: Spiral Descent (hypno spirals, subliminal) +- Level 12: Caption Conditioning (preference-based captions) +- Level 13: Voice + Mind (TTS + hypno, mantras) +- Level 14: Multi-Sensory Assault (quad + spiral + TTS + metronome) +- Level 15: Mind & Body Complete (max features, third checkpoint) +- Level 16: The Interruption (10 interruptions) +- Level 17: Denial Introduction (45 min denial) +- Level 18: Popups & Distractions (20 random popups) +- Level 19: The Gauntlet (60 min, all features, 15 interruptions) +- Level 20: Advanced Training Complete (90 min marathon, fourth checkpoint) +- Hypno spiral display system +- Caption rotation system (preference-based) +- Interruption system (hands-off, verification, humiliation) +- Popup image system +- Denial timer/messaging + +**Measurable Test:** +- [ ] Can complete all levels 11-20 sequentially +- [ ] Hypno spirals display correctly with subliminal messages +- [ ] Caption content matches user preferences +- [ ] Mantras adapt to preferences +- [ ] TTS + hypno coordinate without conflicts +- [ ] Interruptions trigger correctly and pause session +- [ ] Popup images display randomly as specified +- [ ] 90-minute marathon completes successfully +- [ ] Preference checkpoint at L15, library checkpoint at L15 +- [ ] All features coordinate in complex combinations +- [ ] Performance remains acceptable with all features active + +**[📄 View Phase 3 Details](./PHASE-3.md)** + +--- + +### Phase 4: Levels 21-25 Implementation (Path Specialization) +**Priority: MEDIUM** | **Effort: 20-26 hours** | **Status: Not Started** + +Implement path selection and 6 specialized training paths. + +**Key Deliverables:** +- Level 21: Path Selection (questionnaire UI) +- Path filtering based on preferences (e.g., Humiliation requires preference) +- 6 Path Implementations (Levels 22-25 for each): + - **Endurance**: 60min → 90min → 120min → 150min stamina tests + - **Denial**: 7-day → ruined orgasm → 14-day → 30-day challenges + - **Humiliation**: Self-degradation → positions → public fantasy → ultimate degradation + - **Obedience**: 30 interruptions → command sequences → precision timing → perfect exam + - **Sensitivity**: Minimal stim → audio-only → visual triggers → hair-trigger mastery + - **Multi-Sensory**: Triple → quad → five features → all-features overload +- Detailed scenarios for each path level +- Path-specific content and challenges +- Library checkpoint at L25 + +**Measurable Test:** +- [ ] Path selection questionnaire displays at L21 +- [ ] Only available paths shown (based on preferences) +- [ ] Can select a path and progress through L22-25 +- [ ] Each path has unique content/challenges +- [ ] Endurance path increases duration correctly +- [ ] Denial path tracks denial streak +- [ ] Humiliation path respects preference setting +- [ ] Obedience path handles complex interruptions +- [ ] Sensitivity path works with minimal stimulation +- [ ] Multi-Sensory path coordinates all features +- [ ] All 6 paths testable end-to-end +- [ ] Path completion unlocks Level 26 +- [ ] Library statistics show Master Librarian achievement + +**[📄 View Phase 4 Details](./PHASE-4.md)** + +--- + +### Phase 5: Levels 26-30 Implementation (Ultimate Mastery + Graduation) +**Priority: MEDIUM** | **Effort: 16-22 hours** | **Status: Not Started** + +Implement ultimate mastery arc and graduation ceremony. + +**Key Deliverables:** +- Level 26: Return to Foundation (120 min, user-selected features) +- Level 27: The Ascension (150 min, all features, progressive intensity) +- Level 28: Edge of Infinity (180 min, dynamic difficulty) +- Level 29: The Final Crucible (240 min, 4-stage intensity, 40 interruptions) +- Level 30: Graduation (300 min, ultimate test) +- Progressive intensity system (4 stages: Warm-Up → Building → Peak → Overload) +- Dynamic difficulty adjustment +- Milestone photo captures (every 30 min or at % checkpoints) +- Graduation ceremony system: + - Stats summary display + - Photo gallery compilation + - Achievement showcase + - Library curation report (files, tags, curator rank, quality score) + - Preference profile summary + - Graduation oath (preference-based) + - Certificate generation +- Freeplay mode unlock +- Ascended Mode unlock (secret post-graduation) + +**Measurable Test:** +- [ ] Level 26 allows user feature selection +- [ ] Level 27 progressive intensity works (4 stages) +- [ ] Level 28 dynamic difficulty adjusts based on performance +- [ ] Level 29 handles 240 minutes with 40 interruptions +- [ ] Level 30 completes full 300-minute session +- [ ] Milestone photos capture correctly +- [ ] Graduation ceremony displays all stats +- [ ] Library report shows accurate data +- [ ] Graduation oath adapts to preferences +- [ ] Certificate generates with correct info +- [ ] Freeplay mode unlocks after graduation +- [ ] Ascended Mode unlocks and functions +- [ ] Can replay any completed level +- [ ] All 30 levels tested in sequence from L1 → L30 + +**[📄 View Phase 5 Details](./PHASE-5.md)** + +--- + +### Phase 6: Progression, Stats, Achievements & Library System +**Priority: HIGH** | **Effort: 14-18 hours** | **Status: Not Started** + +Build comprehensive tracking systems that span entire campaign. + +**Key Deliverables:** +- `trainingStats` data structure (sessions, time, levels, feature usage) +- 25+ achievement system: + - Campaign achievements (complete levels/arcs) + - Library achievements (tag coverage, file count, curator rank) + - Feature achievements (use specific features) + - Ultimate achievements (flawless denial, all photos, etc.) +- Achievement notification system (modals, toasts) +- Stats dashboard UI: + - Campaign progress (levels completed, current arc) + - Time statistics (total time, per-level time) + - Library statistics (files, tags, coverage, quality score) + - Feature usage tracking + - Achievement gallery + - Curator rank display +- Persistent data management (save/load across sessions) +- Denial streak tracking +- Library quality scoring algorithm +- Diversity scoring algorithm +- Smart playlist system from tag combinations + +**Measurable Test:** +- [ ] Stats persist across page refreshes +- [ ] Completing level updates stats correctly +- [ ] Achievements unlock at correct triggers +- [ ] Achievement notifications display correctly +- [ ] Stats dashboard shows accurate data +- [ ] Library statistics calculate correctly +- [ ] Tag coverage percentage accurate +- [ ] Curator rank advances based on tag coverage +- [ ] Quality score reflects library organization +- [ ] Diversity score reflects content variety +- [ ] Denial streak tracks correctly +- [ ] Smart playlists filter by tags correctly +- [ ] Can export/import campaign data +- [ ] All 25+ achievements are obtainable + +**[📄 View Phase 6 Details](./PHASE-6.md)** + +--- + +### Phase 7: Polish, UI/UX, Accessibility & Testing +**Priority: MEDIUM-LOW** | **Effort: 12-16 hours** | **Status: Not Started** + +Final polish, quality of life features, and comprehensive testing. + +**Key Deliverables:** +- UI/UX improvements: + - Dark mode / theme customization + - Smooth transitions and animations + - Responsive design (mobile consideration) + - Loading states and progress indicators + - Onboarding tutorial for new users +- Accessibility features: + - Safe word / emergency stop button + - Keyboard navigation + - Pause system (pause during interruptions, resume) + - Session recovery (browser crash recovery) + - Adjustable text size +- Quality of life: + - Quick session retry (restart failed level) + - Skip tutorial option (for replays) + - Custom session duration multiplier + - Library bulk operations (bulk tag, bulk import) + - Export library metadata +- Performance optimization: + - Lazy loading of videos/images + - Tag search indexing + - Efficient DOM updates +- Comprehensive testing: + - L1 → L30 full playthrough + - All 6 paths tested + - All features tested in isolation and combination + - Edge cases (browser refresh, tab switching, etc.) + - Performance testing (library with 10,000+ files) +- Bug fixes and error handling +- Documentation (in-game help, tooltips) + +**Measurable Test:** +- [ ] Dark mode toggles correctly +- [ ] All UI transitions smooth (no jank) +- [ ] Safe word immediately stops session +- [ ] Keyboard shortcuts work throughout +- [ ] Pause/resume works correctly +- [ ] Session recovery restores state after crash +- [ ] Can retry failed level immediately +- [ ] Tutorial can be skipped on replay +- [ ] Bulk tagging 100 files works quickly +- [ ] Library with 5,000 files performs well +- [ ] Tag search returns results in <100ms +- [ ] No console errors during full playthrough +- [ ] No memory leaks during long sessions +- [ ] All tooltips/help text accurate +- [ ] Full L1→L30 playthrough successful +- [ ] All 6 paths completable +- [ ] All features functional in all combinations + +**[📄 View Phase 7 Details](./PHASE-7.md)** + +--- + +## ⏱️ Total Estimated Effort + +| Phase | Priority | Hours | Status | Dependencies | +|-------|----------|-------|--------|--------------| +| Phase 1 | HIGHEST | 12-16 | Not Started | None | +| Phase 2 | HIGH | 16-20 | Not Started | Phase 1 | +| Phase 3 | HIGH | 18-24 | Not Started | Phase 1, 2 | +| Phase 4 | MEDIUM | 20-26 | Not Started | Phase 1, 2, 3 | +| Phase 5 | MEDIUM | 16-22 | Not Started | Phase 1, 2, 3, 4 | +| Phase 6 | HIGH | 14-18 | Not Started | Phase 1 | +| Phase 7 | MEDIUM-LOW | 12-16 | Not Started | All | +| **TOTAL** | | **108-142** | **0% Complete** | | + +--- + +## 🎯 Recommended Implementation Order + +**Parallel Track Strategy:** + +**Track A (Campaign Content):** +1. Phase 1 (Foundation) → Phase 2 (L1-10) → Phase 3 (L11-20) → Phase 4 (L21-25) → Phase 5 (L26-30) + +**Track B (Systems):** +1. Phase 6 (Stats/Achievements/Library) - Can start after Phase 1 + +**Track C (Polish):** +1. Phase 7 (UI/UX/Testing) - Continuous throughout, finalize at end + +**Recommended Sequence:** +1. **Phase 1** (12-16 hours) - Foundation systems (MUST complete first) +2. **Phase 6** (14-18 hours) - Stats/library systems (start after Phase 1, work in parallel) +3. **Phase 2** (16-20 hours) - Levels 1-10 (can start during Phase 6) +4. **Phase 3** (18-24 hours) - Levels 11-20 +5. **Phase 4** (20-26 hours) - Levels 21-25 (Path specialization) +6. **Phase 5** (16-22 hours) - Levels 26-30 (Ultimate + Graduation) +7. **Phase 7** (12-16 hours) - Polish and final testing + +**Rationale**: Build foundation first, then systems and content in parallel, polish at end. + +--- + +## 🔧 Technical Architecture + +### New Files to Create: + +**Campaign Management:** +- `src/features/academy/campaignManager.js` - Level unlocking, progression, failure states +- `src/features/academy/preferenceManager.js` - User preferences, content filtering +- `src/features/academy/libraryManager.js` - Media library, tagging, filtering +- `src/features/academy/tagManager.js` - Tag CRUD operations, suggestions, validation + +**Data Structures:** +- `src/data/modes/academyLevelData.js` - All 30 level definitions +- `src/data/academy/achievements.js` - Achievement definitions +- `src/data/academy/pathData.js` - 6 specialized path data + +**Systems:** +- `src/features/academy/progressionManager.js` - Stats, achievements, levels +- `src/features/academy/graduationManager.js` - Ceremony, certificate, unlocks +- `src/features/academy/intensityManager.js` - Progressive intensity scaling + +### Files to Update: + +**Core:** +- `src/features/tasks/interactiveTaskManager.js` - New action handlers for all level types +- `src/core/gameDataManager.js` - Add academyProgress, preferences, libraryData persistence +- `training-academy.html` - Complete UI overhaul for campaign + +**Integration:** +- `src/features/video/videoPlayerManager.js` - Tag-based video selection +- `src/features/images/popupImageManager.js` - Tag-based image selection +- `src/features/webcam/webcamManager.js` - Milestone photo captures +- `src/features/tts/voiceManager.js` - Preference-based script generation + +### Data Flow: + +``` +User launches Academy + ↓ +campaignManager loads academyProgress + ↓ +Display level select UI (show unlocked levels) + ↓ +User selects level N + ↓ +If checkpoint level (1,5,10,15,20,25): + → Show preference form + → Show library maintenance UI + ↓ +Load level data from academyLevelData.js + ↓ +Initialize required features based on level + ↓ +Run level session (interactiveTaskManager) + ↓ +Monitor for: + - Cumming (fail) + - Feature closure (fail) + - Interruptions (handle) + - Time milestones (photos) + ↓ +Session completes: + - Update stats (time, features used) + - Check achievements + - Update library stats (if tagging done) + - Unlock next level + - Save all data + ↓ +Display completion screen + ↓ +If Level 30: + → Launch graduation ceremony + → Generate certificate + → Unlock freeplay/ascended +``` + +--- + +## 💡 Key Integration Principles + +1. **Feature Modularity**: Each feature can be enabled/disabled independently +2. **Graceful Degradation**: If webcam unavailable, session continues without it +3. **Progressive Disclosure**: Features unlock gradually, preventing overwhelm +4. **User Control**: Preferences shape content, tags filter media +5. **Performance Awareness**: Lazy load media, efficient tag indexing +6. **Data Privacy**: All webcam photos stay local, user controls deletion +7. **Accessibility**: Safe word, keyboard nav, pause system always available +8. **Testing**: Test each level individually, then full campaign playthrough +9. **Progression Gating**: Can't skip levels, ensures proper learning curve +10. **Replay Value**: Can replay any completed level for better stats/photos + +--- + +## 🎓 Feature Unlocking Schedule + +| Level | Feature Unlocked | Why | +|-------|-----------------|-----| +| 1 | Basic timer | Foundation | +| 2 | Directory tagging | Library curation begins | +| 3 | Audio metronome, File tagging | Rhythm + organization | +| 4 | Video player (single) | Visual stimulation | +| 5 | Webcam mirror | Self-awareness | +| 6 | Auto-capture photos | Documentation | +| 7 | Dual video | Increased stimulation | +| 8 | TTS coaching | Voice control | +| 9 | Quad video | Maximum visual overload | +| 10 | Extended tier, Smart playlists | Longer sessions, better organization | +| 11 | Hypno spirals | Mind control | +| 12 | Captions, Popups | Mental conditioning | +| 13 | TTS+Hypno combo | Deep trance | +| 14 | Multi-feature coordination | Complex orchestration | +| 15 | Interruptions, Marathon tier | Ultimate control testing | +| 20 | All features unlocked | Complete arsenal | +| 21 | Path selection | Specialization | +| 26 | Custom feature selection | Mastery through choice | +| 30 | Freeplay, Ascended Mode | Post-graduation freedom | + +--- + +## 📈 Success Criteria (Overall Project) + +### Minimum Viable Campaign (MVC): +- [ ] All 30 levels implemented +- [ ] Level progression works (L1 → L30) +- [ ] All features unlock correctly +- [ ] Preference system functional +- [ ] Library tagging system functional +- [ ] Stats persist across sessions +- [ ] Can complete full campaign (L1 → L30) +- [ ] Graduation ceremony works + +### Full Campaign (Ideal): +- [ ] All above + measurable tests from each phase pass +- [ ] All 6 paths functional +- [ ] All 25+ achievements obtainable +- [ ] Library quality/diversity scoring works +- [ ] Smart playlists functional +- [ ] Freeplay and Ascended Mode work +- [ ] No performance issues with large libraries +- [ ] Full UI polish complete +- [ ] All accessibility features work + +--- + +## 🚦 Current Status + +**Last Updated**: November 29, 2025 +**Current Phase**: Design Complete, Implementation Not Started +**Overall Progress**: 0% +**Documentation Status**: Campaign structure complete, phase docs need updating + +**Next Actions**: +1. Review and approve campaign structure +2. Update all 7 phase documents to align with campaign +3. Begin Phase 1 implementation (foundation systems) + +--- + +## 📞 Quick Reference + +**Campaign Design**: [CAMPAIGN-STRUCTURE.md](./CAMPAIGN-STRUCTURE.md) +**Phase Documents**: See table at top of this document +**Current Files**: +- Training data: `src/data/modes/trainingGameData.js` (will be replaced/supplemented) +- Task manager: `src/features/tasks/interactiveTaskManager.js` (will be updated) +- UI: `training-academy.html` (will be overhauled) + +--- + +## 🎯 Vision Statement + +**The Academy is the crowning jewel of the entire project.** + +It transforms random edging sessions into a structured journey of growth and mastery. Users don't just edge—they progress through a carefully designed campaign that teaches discipline through library curation, self-awareness through webcam mirror sessions, endurance through progressively longer levels, and obedience through interruption challenges. + +Every level has purpose. Every feature unlocks at the right moment. Every preference matters. Every tag contributes to a perfectly curated experience. + +Users enter as curious beginners. They leave as perfect gooners with impeccably organized libraries, fully customized preferences, and complete mastery of all features. + +**This is not just a training game. This is The Academy. This is transformation.** + +Let's build it. diff --git a/docs/training-game-redesign/PHASE-1.md b/docs/training-game-redesign/PHASE-1.md new file mode 100644 index 0000000..5046b35 --- /dev/null +++ b/docs/training-game-redesign/PHASE-1.md @@ -0,0 +1,500 @@ +# Phase 1: Campaign Foundation & Core Systems + +**Priority**: HIGHEST - Must complete first +**Estimated Effort**: 12-16 hours +**Status**: In Progress +**Dependencies**: None + +--- + +## 📝 Subphase Tracking + +- [x] **Subphase 1.1**: Campaign Progression System (2-3 hrs) - ✅ COMPLETE - User tested and confirmed +- [x] **Subphase 1.2**: Preference Management System (2-3 hrs) - ✅ COMPLETE - User tested and confirmed +- [x] **Subphase 1.3**: Library Tagging System (2-3 hrs) - ✅ COMPLETE - User tested and confirmed +- [x] **Subphase 1.4**: Content Filtering & UI (2-3 hrs) - ✅ COMPLETE - Awaiting user test + +**⚠️ IMPORTANT**: After each subphase implementation, WAIT for user to test and confirm before proceeding to next subphase. + +--- + +## 🎯 Phase Goals + +Build the foundational systems required for The Academy's 30-level campaign structure, including campaign progression, preference management, and media library tagging. + +--- + +## 📋 What This Phase Delivers + +### Core Systems: +1. **Campaign Progression System** - Level unlocking, completion tracking, failure states +2. **Preference Management System** - User preferences with checkpoint updates +3. **Media Library Tagging System** - Directory and individual file tagging +4. **Tag-Based Content Filtering** - Filter videos/images by preferences and tags +5. **Data Persistence** - Save/load campaign progress, preferences, library data +6. **Basic UI Infrastructure** - Level selection, preference forms, library management + +**End Result**: Foundation that all 30 levels will build upon. + +--- + +## 🏗️ Implementation Tasks + +### Task 1: Campaign Progression System (4-5 hours) + +**File to Create**: `src/features/academy/campaignManager.js` + +**Responsibilities**: +- Track which levels are unlocked (start with only Level 1) +- Handle level completion (unlock next level) +- Track current level, highest completed level +- Handle failure states (cumming, abandoning session, feature closure) +- Manage level restart on failure +- Save/load campaign state + +**Data Structure** (in `gameData.js`): +```javascript +academyProgress: { + version: 1, + currentLevel: 1, + highestUnlockedLevel: 1, + completedLevels: [], // array of level numbers completed + currentArc: 'Foundation', // Foundation, Feature Discovery, etc. + failedAttempts: {}, // { levelNum: count } + totalSessionTime: 0, // seconds across all levels + lastPlayedLevel: null, + lastPlayedDate: null, + graduationCompleted: false, + freeplayUnlocked: false, + ascendedModeUnlocked: false +} +``` + +**Key Methods**: +```javascript +class CampaignManager { + constructor() { + this.loadProgress(); + } + + // Get list of unlocked levels + getUnlockedLevels() { + // Returns array: [1, 2, 3, ...highestUnlockedLevel] + } + + // Check if level is unlocked + isLevelUnlocked(levelNum) { + // Returns true if levelNum <= highestUnlockedLevel + } + + // Start a level + startLevel(levelNum) { + // Validates level is unlocked + // Loads level data + // Returns level config or error + } + + // Complete a level + completeLevel(levelNum, sessionData) { + // Add to completedLevels + // Unlock next level + // Update stats + // Check for arc completion + // Save progress + // Return: { nextLevelUnlocked, achievements, arcComplete } + } + + // Fail a level + failLevel(levelNum, reason) { + // Increment failedAttempts + // Log failure reason ('cumming', 'abandoned', 'feature-closed') + // Save progress + } + + // Get current arc + getCurrentArc() { + // Based on current level, return arc name + // L1-5: Foundation + // L6-10: Feature Discovery + // L11-15: Mind & Body + // L16-20: Advanced Training + // L21-25: Path Specialization + // L26-30: Ultimate Mastery + } + + // Check if level is a checkpoint + isCheckpointLevel(levelNum) { + // Returns true for levels 1, 5, 10, 15, 20, 25 + } + + // Save/load + saveProgress() { /* save to gameData */ } + loadProgress() { /* load from gameData */ } +} +``` + +**Testing Checklist**: +- [ ] Can start Level 1 +- [ ] Completing L1 unlocks L2 +- [ ] Cannot start L2 before completing L1 +- [ ] Failing L1 allows restart +- [ ] Progress persists across page refresh +- [ ] Arc detection works correctly +- [ ] Checkpoint detection works for L1, L5, L10, etc. + +--- + +### Task 2: Preference Management System (3-4 hours) + +**File to Create**: `src/features/academy/preferenceManager.js` + +**Responsibilities**: +- Display preference form at checkpoint levels +- Save user preferences +- Filter content based on preferences +- Generate preference-based text (captions, mantras, oaths) + +**Data Structure** (in `gameData.js`): +```javascript +academyPreferences: { + lastUpdatedLevel: 1, + contentThemes: { + sissy: false, + humiliation: false, + worship: false, + denial: false, + obedience: true, + bimbo: false, + findom: false, + edging: true // always true + }, + visualPreferences: { + amateur: true, + professional: true, + hentai: false, + bodyTypes: ['curvy', 'athletic'], + specificContent: [] // 'feet', 'BBC', etc. + }, + intensity: { + soft: false, + moderate: true, + harsh: false, + extreme: false + }, + captionTone: { + neutral: true, + masculine: false, + feminine: false, + motivational: true, + degrading: false + } +} +``` + +**Key Methods**: +```javascript +class PreferenceManager { + // Display preference form (at checkpoints) + showPreferenceForm(levelNum) { + // Generate HTML form with checkboxes + // Pre-fill with current preferences + // Return promise that resolves when user submits + } + + // Save preferences + savePreferences(prefs) { + // Update academyPreferences in gameData + // Set lastUpdatedLevel + // Save to storage + } + + // Get preferences + getPreferences() { + // Return current preferences + } + + // Check if theme is enabled + isThemeEnabled(theme) { + // Returns true if contentThemes[theme] === true + } + + // Get enabled themes + getEnabledThemes() { + // Returns array of enabled theme names + } + + // Generate preference-based text + generateMantra() { + // Based on enabled themes, return appropriate mantra + // e.g., sissy enabled: "I am a sissy gooner..." + } + + generateCaptionTags() { + // Returns array of caption tags based on themes + // Used to filter caption images + } + + // Filter content by preferences + matchesPreferences(contentTags) { + // Given array of tags, check if matches user preferences + // Returns true if compatible + } +} +``` + +**UI Components Needed**: +```html + +
+

Set Your Preferences

+

Customize your Academy experience.

+ +
+

Content Themes

+ + + + + + + +
+ + + + +
+``` + +**Testing Checklist**: +- [ ] Preference form appears at L1 +- [ ] Can select/deselect preferences +- [ ] Preferences save to gameData +- [ ] Preferences persist across refresh +- [ ] Content filtering respects preferences +- [ ] Mantra generation adapts to preferences + +--- + +### Task 3: Media Library Tagging System (4-5 hours) + +**Files to Create**: +- `src/features/academy/libraryManager.js` +- `src/features/academy/tagManager.js` + +**Responsibilities**: +- Add directories to library +- Tag directories (bulk tags for all files in directory) +- Tag individual files (specific tags per file) +- Calculate tag coverage percentage +- Track curator rank +- Display library statistics + +**Data Structure** (in `gameData.js`): +```javascript +libraryData: { + directories: [ + { + path: '/assets/BBC/', + tags: ['bbc', 'interracial'], + addedAtLevel: 2, + fileCount: 47, + subdirectories: [...] + } + ], + individualFiles: [ + { + path: '/assets/BBC/amateur/video01.mp4', + type: 'video', + duration: 272, + quality: '1080p', + directoryTags: ['bbc', 'interracial', 'amateur'], + customTags: ['pov', 'blowjob'], + allTags: ['bbc', 'interracial', 'amateur', 'pov', 'blowjob'], + taggedAtLevel: 3, + timesPlayed: 12 + } + ], + statistics: { + totalFiles: 1247, + taggedFiles: 1200, + untaggedFiles: 47, + tagCoverage: 96.2, + curatorRank: 'Expert', + totalTags: 2847, + uniqueTags: 87, + topTags: [ + { tag: 'amateur', count: 423 } + ] + } +} +``` + +**Key Methods**: + +```javascript +class LibraryManager { + addDirectory(path, tags = []) { /* Add to directories array */ } + tagDirectory(path, tags) { /* Add tags to directory */ } + tagFile(filePath, tags) { /* Add custom tags to specific file */ } + getFileTags(filePath) { /* Return allTags for a file */ } + getFilesByTags(tags, matchMode = 'AND') { /* Filter files by tags */ } + updateStatistics() { /* Calculate totals, coverage %, curator rank */ } + getCuratorRank() { + // <50%: Novice, 50-75%: Apprentice, 75-90%: Journeyman + // 90-98%: Expert, 98-100%: Master + } +} + +class TagManager { + getAllTags() { /* Return comprehensive tag list */ } + suggestTags(filename) { /* Parse filename for keywords */ } + isValidTag(tag) { /* Check if tag exists in catalog */ } + addCustomTag(tag) { /* Allow user-defined tags */ } +} +``` + +**UI Components**: +- Directory tagging form +- File tagging form +- Library statistics dashboard + +**Testing Checklist**: +- [ ] Can add directory with tags +- [ ] Can tag individual file +- [ ] File inherits directory tags +- [ ] Tag coverage calculates correctly +- [ ] Curator rank advances based on coverage +- [ ] Statistics persist across refresh + +--- + +### Task 4: Tag-Based Content Filtering (2-3 hours) + +**File to Update**: `src/features/video/videoLibrary.js` + +**New Methods**: +```javascript +class VideoLibrary { + getVideosByTags(tags, matchMode = 'AND') { + // Use LibraryManager to get matching files + // Filter by type === 'video' + } + + getVideosByPreferences(preferences) { + // Convert preferences to tags + // Use getVideosByTags + } + + getRandomVideo(tags = null, preferences = null) { + // Filter by tags/preferences, return random + } +} +``` + +**Testing Checklist**: +- [ ] Video filtering by tags works +- [ ] Preference-based filtering works +- [ ] Returns null gracefully if no matches + +--- + +### Task 5: Data Persistence (1-2 hours) + +**File to Update**: `src/core/gameDataManager.js` + +Add academy data structures and ensure save/load works. + +**Testing Checklist**: +- [ ] All academy data saves +- [ ] All academy data loads on refresh +- [ ] Existing saves migrate without errors + +--- + +### Task 6: Basic UI Infrastructure (2-3 hours) + +**File to Update**: `training-academy.html` + +Add: +- Level select screen (30 level buttons) +- Checkpoint modal (preferences/library tabs) +- Level completion screen + +**Testing Checklist**: +- [ ] Level select screen displays +- [ ] Locked levels appear disabled +- [ ] Checkpoint modal appears correctly +- [ ] Level completion screen shows stats + +--- + +## 📏 Measurable Test Criteria + +After Phase 1, ALL of these must pass: + +### Campaign Progression: +- [ ] Can select and start Level 1 +- [ ] Completing Level 1 unlocks Level 2 +- [ ] Cannot start Level 2 before completing Level 1 +- [ ] Failing Level 1 allows restart +- [ ] Progress persists across refresh +- [ ] Current arc displays correctly + +### Preferences: +- [ ] Preference form appears at Level 1 +- [ ] Preferences save and persist +- [ ] Preference form appears at Level 5 + +### Library Tagging: +- [ ] Can add directory with tags at Level 2 +- [ ] Can tag individual file at Level 3 +- [ ] Tag coverage calculates correctly +- [ ] Curator rank displays +- [ ] Library statistics persist + +### Content Filtering: +- [ ] Can filter videos by tags +- [ ] Preference filtering works + +### Data Persistence: +- [ ] All data saves and loads correctly +- [ ] No console errors + +### UI: +- [ ] Level select renders 30 levels +- [ ] Checkpoint modal functional +- [ ] Level completion screen displays + +--- + +## 🎯 Success Criteria + +**Phase 1 Complete When:** +1. All 6 tasks implemented +2. All measurable tests pass +3. No console errors +4. Can complete L1 → unlock L2 → checkpoint at L5 +5. Library tagging works at L2-3 +6. All data persists + +--- + +## 📂 Files Created/Modified + +### New Files: +- `src/features/academy/campaignManager.js` +- `src/features/academy/preferenceManager.js` +- `src/features/academy/libraryManager.js` +- `src/features/academy/tagManager.js` + +### Modified Files: +- `src/core/gameDataManager.js` +- `src/features/video/videoLibrary.js` +- `training-academy.html` + +--- + +## 🚀 Next Phase + +After Phase 1: **Phase 2: Levels 1-10 Implementation** diff --git a/docs/training-game-redesign/PHASE-2.md b/docs/training-game-redesign/PHASE-2.md new file mode 100644 index 0000000..59c77de --- /dev/null +++ b/docs/training-game-redesign/PHASE-2.md @@ -0,0 +1,678 @@ +# Phase 2: Levels 1-10 Implementation + +**Priority**: HIGH - Core tutorial and early progression +**Estimated Effort**: 16-20 hours +**Status**: Not Started +**Dependencies**: Phase 1 (Campaign Foundation) + +--- + +## 🎯 Phase Goals + +Implement the first 10 levels of The Academy, covering the **Foundation Arc** (L1-5) and **Feature Discovery Arc** (L6-10). These levels introduce basic edging, build to complex feature combinations, and include the first preference checkpoint. + +--- + +## 📋 What This Phase Delivers + +### Arcs Implemented: +1. **Foundation Arc (L1-5)**: Basic edging, rhythm, video introduction, library setup +2. **Feature Discovery Arc (L6-10)**: Webcam, dual video, TTS, quad video, hypno spiral + +### Level-by-Level: +- **L1**: Edge Training 101 (5min) - Basic edges +- **L2**: Rhythm & Control (10min) - Rhythm patterns + library addition +- **L3**: Visual Immersion (15min) - First porn video + file tagging +- **L4**: Multi-Tasking Challenge (20min) - Multiple actions, rhythm + video +- **L5**: Foundation Checkpoint (25min) - Preference update + L1-4 recap +- **L6**: The Observer (30min) - Webcam unlock +- **L7**: Dual Focus (40min) - Picture-in-picture dual video +- **L8**: Vocal Commands (50min) - TTS unlock +- **L9**: Sensory Array (60min) - Quad video unlock +- **L10**: Hypnotic Gateway (70min) - Hypno spiral unlock + Checkpoint + +**End Result**: Fully functional early campaign with progressive feature unlocking. + +--- + +## 🏗️ Implementation Tasks + +### Task 1: Action Handler Extensions (6-8 hours) + +**File to Update**: `src/features/tasks/interactiveTaskManager.js` + +Add handlers for new actions used in L1-10: + +#### New Action Types Needed: + +**Basic Actions (L1-5)**: +```javascript +{ + type: 'edge', + params: { + count: 5, + instruction: 'Edge 5 times in a row' + } +} + +{ + type: 'rhythm', + params: { + pattern: 'slow-fast-slow', // or 'fast-slow-fast', 'steady' + duration: 120 + } +} + +{ + type: 'add-library-directory', + params: { + directory: '/assets/amateur/', + suggestedTags: ['amateur', 'solo'] + } +} + +{ + type: 'tag-files', + params: { + directory: '/assets/amateur/', + minFiles: 10, + suggestedTags: ['pov', 'blowjob', 'riding'] + } +} +``` + +**Feature Unlock Actions (L6-10)**: +```javascript +{ + type: 'enable-webcam', + params: { + instruction: 'Turn on your webcam to watch yourself' + } +} + +{ + type: 'dual-video', + params: { + mainVideo: 'focus', + pipVideo: 'overlay', + pipPosition: 'bottom-right' + } +} + +{ + type: 'tts-command', + params: { + text: 'Good gooner. Edge again.', + voice: 'feminine' + } +} + +{ + type: 'quad-video', + params: { + layout: 'grid', // or 'cascade' + videos: ['random', 'random', 'random', 'random'] + } +} + +{ + type: 'hypno-spiral', + params: { + duration: 120, + overlay: true, + opacity: 0.5 + } +} +``` + +#### Handler Implementation: + +```javascript +class InteractiveTaskManager { + // ... existing code ... + + async handleEdgeAction(action) { + // Show edge counter UI + // Wait for user to edge X times + // Track edge count + // Return when complete + } + + async handleRhythmAction(action) { + // Display rhythm pattern indicator + // Play metronome sounds + // Track user compliance + } + + async handleAddLibraryAction(action) { + // Call LibraryManager.addDirectory + // Show success message + } + + async handleTagFilesAction(action) { + // Open tagging UI + // Pre-fill directory and suggestions + // Wait for user to tag N files + // Update library stats + } + + async handleEnableWebcamAction(action) { + // Call WebcamManager.start() + // Show webcam in overlay + // Mark webcam as unlocked + } + + async handleDualVideoAction(action) { + // Load main video in FocusVideoPlayer + // Load PiP video in OverlayVideoPlayer + // Position PiP + } + + async handleTTSAction(action) { + // Call VoiceManager.speak() + // Wait for speech to finish + } + + async handleQuadVideoAction(action) { + // Initialize QuadVideoPlayer + // Load 4 random videos + // Display in grid layout + } + + async handleHypnoSpiralAction(action) { + // Show hypno spiral overlay + // Animate spiral + // Play hypno audio + // Run for duration + } +} +``` + +**Testing Checklist**: +- [ ] Edge action tracks count correctly +- [ ] Rhythm action displays pattern +- [ ] Library directory adds successfully +- [ ] File tagging UI works +- [ ] Webcam enables correctly +- [ ] Dual video displays properly +- [ ] TTS speaks commands +- [ ] Quad video grid renders +- [ ] Hypno spiral animates + +--- + +### Task 2: Level Data Definitions (4-5 hours) + +**File to Create**: `src/data/modes/academyLevelData.js` + +Define all 30 levels. For Phase 2, implement L1-10 in detail: + +```javascript +const academyLevels = { + 1: { + name: "Edge Training 101", + arc: "Foundation", + duration: 300, // 5 minutes + requirements: { + minLevel: 1, + featuresRequired: [] + }, + unlocks: { + level: 2, + features: [] + }, + sessionStructure: { + warmup: [ + { type: 'caption', text: 'Welcome to The Academy, gooner.' }, + { type: 'instruction', text: 'Today you learn the basics of edging.' } + ], + main: [ + { type: 'edge', params: { count: 5, instruction: 'Edge 5 times slowly' } }, + { type: 'wait', duration: 30 }, + { type: 'edge', params: { count: 3, instruction: 'Edge 3 more times' } } + ], + cooldown: [ + { type: 'caption', text: 'You completed your first level!' }, + { type: 'save-progress' } + ] + }, + failureConditions: { + cumming: true, + closingFeatures: false, // no features to close yet + abandoningSession: true + } + }, + + 2: { + name: "Rhythm & Control", + arc: "Foundation", + duration: 600, // 10 minutes + requirements: { + minLevel: 2, + completedLevels: [1] + }, + unlocks: { + level: 3, + features: [] + }, + sessionStructure: { + warmup: [ + { type: 'caption', text: 'Level 2: Learning rhythm and building your library.' } + ], + main: [ + { type: 'rhythm', params: { pattern: 'slow-fast-slow', duration: 180 } }, + { type: 'add-library-directory', params: { + directory: '/assets/amateur/', + suggestedTags: ['amateur', 'solo'] + }}, + { type: 'edge', params: { count: 10 } } + ], + cooldown: [ + { type: 'caption', text: 'Your library is growing...' } + ] + }, + failureConditions: { + cumming: true, + abandoningSession: true + } + }, + + 3: { + name: "Visual Immersion", + arc: "Foundation", + duration: 900, // 15 minutes + requirements: { + minLevel: 3, + completedLevels: [2] + }, + unlocks: { + level: 4, + features: ['video'] + }, + sessionStructure: { + warmup: [ + { type: 'caption', text: 'Time to add visuals to your training.' } + ], + main: [ + { type: 'video-start', params: { player: 'focus', tags: ['amateur'] } }, + { type: 'tag-files', params: { + directory: '/assets/amateur/', + minFiles: 10, + suggestedTags: ['pov', 'blowjob', 'riding'] + }}, + { type: 'edge', params: { count: 15 } }, + { type: 'video-stop' } + ], + cooldown: [] + }, + failureConditions: { + cumming: true, + abandoningSession: true, + closingFeatures: ['video'] + } + }, + + 4: { + name: "Multi-Tasking Challenge", + arc: "Foundation", + duration: 1200, // 20 minutes + requirements: { + minLevel: 4, + completedLevels: [3] + }, + unlocks: { + level: 5 + }, + sessionStructure: { + warmup: [], + main: [ + { type: 'video-start', params: { player: 'focus' } }, + { type: 'rhythm', params: { pattern: 'fast-slow-fast', duration: 240 } }, + { type: 'edge', params: { count: 20 } }, + { type: 'caption', text: 'Keep going... faster...' } + ], + cooldown: [] + } + }, + + 5: { + name: "Foundation Checkpoint", + arc: "Foundation", + duration: 1500, // 25 minutes + isCheckpoint: true, + requirements: { + minLevel: 5, + completedLevels: [4] + }, + unlocks: { + level: 6, + features: [], + arcsCompleted: ['Foundation'] + }, + sessionStructure: { + warmup: [ + { type: 'show-preferences', reason: 'checkpoint' } + ], + main: [ + // Recap of L1-4 techniques + { type: 'edge', params: { count: 5 } }, + { type: 'rhythm', params: { pattern: 'slow-fast-slow', duration: 120 } }, + { type: 'video-start' }, + { type: 'edge', params: { count: 25 } } + ], + cooldown: [ + { type: 'show-arc-complete', arc: 'Foundation' } + ] + } + }, + + 6: { + name: "The Observer", + arc: "Feature Discovery", + duration: 1800, // 30 minutes + requirements: { + minLevel: 6, + completedLevels: [5] + }, + unlocks: { + level: 7, + features: ['webcam'] + }, + sessionStructure: { + warmup: [ + { type: 'caption', text: 'Welcome to Feature Discovery. Time to watch yourself.' } + ], + main: [ + { type: 'enable-webcam' }, + { type: 'video-start' }, + { type: 'caption', text: 'Watch yourself gooning...' }, + { type: 'edge', params: { count: 30 } } + ], + cooldown: [] + }, + failureConditions: { + cumming: true, + abandoningSession: true, + closingFeatures: ['webcam', 'video'] + } + }, + + 7: { + name: "Dual Focus", + arc: "Feature Discovery", + duration: 2400, // 40 minutes + requirements: { + minLevel: 7, + completedLevels: [6], + featuresUnlocked: ['webcam'] + }, + unlocks: { + level: 8, + features: ['dual-video'] + }, + sessionStructure: { + main: [ + { type: 'dual-video', params: { mainVideo: 'focus', pipVideo: 'overlay' } }, + { type: 'edge', params: { count: 40 } } + ] + } + }, + + 8: { + name: "Vocal Commands", + arc: "Feature Discovery", + duration: 3000, // 50 minutes + requirements: { + minLevel: 8, + completedLevels: [7], + featuresUnlocked: ['dual-video'] + }, + unlocks: { + level: 9, + features: ['tts'] + }, + sessionStructure: { + main: [ + { type: 'enable-tts' }, + { type: 'video-start' }, + { type: 'tts-command', params: { text: 'Edge for me, gooner.' } }, + { type: 'edge', params: { count: 50 } }, + { type: 'tts-command', params: { text: 'Good gooner. Keep going.' } } + ] + } + }, + + 9: { + name: "Sensory Array", + arc: "Feature Discovery", + duration: 3600, // 60 minutes + requirements: { + minLevel: 9, + completedLevels: [8], + featuresUnlocked: ['tts'] + }, + unlocks: { + level: 10, + features: ['quad-video'] + }, + sessionStructure: { + main: [ + { type: 'quad-video', params: { layout: 'grid' } }, + { type: 'tts-command', params: { text: 'Watch all four screens...' } }, + { type: 'edge', params: { count: 60 } } + ] + } + }, + + 10: { + name: "Hypnotic Gateway", + arc: "Feature Discovery", + duration: 4200, // 70 minutes + isCheckpoint: true, + requirements: { + minLevel: 10, + completedLevels: [9], + featuresUnlocked: ['quad-video'] + }, + unlocks: { + level: 11, + features: ['hypno'], + arcsCompleted: ['Feature Discovery'] + }, + sessionStructure: { + warmup: [ + { type: 'show-preferences', reason: 'checkpoint' } + ], + main: [ + { type: 'hypno-spiral', params: { duration: 120, overlay: true } }, + { type: 'quad-video' }, + { type: 'tts-command', params: { text: 'Deeper... watch the spiral...' } }, + { type: 'edge', params: { count: 70 } } + ], + cooldown: [ + { type: 'show-arc-complete', arc: 'Feature Discovery' } + ] + } + } +}; + +export default academyLevels; +``` + +**Testing Checklist**: +- [ ] All 10 levels defined +- [ ] Level requirements check correctly +- [ ] Unlocks work as specified +- [ ] Checkpoint levels trigger preferences + +--- + +### Task 3: UI Components for Levels (3-4 hours) + +**File to Update**: `training-academy.html` + +Add UI elements: + +```html + + + + + + + +
+ + +
+``` + +**Testing Checklist**: +- [ ] Level complete modal displays stats +- [ ] Arc complete modal shows at L5 and L10 +- [ ] Level select shows L1-10 unlockable + +--- + +### Task 4: Feature Unlock Integration (2-3 hours) + +Connect action handlers to actual feature managers: + +**Webcam Unlock** → `WebcamManager.start()` +**Dual Video** → `FocusVideoPlayer` + `OverlayVideoPlayer` +**TTS** → `VoiceManager.speak()` +**Quad Video** → `QuadVideoPlayer.initialize()` +**Hypno** → Create hypno spiral overlay + +**Testing Checklist**: +- [ ] Webcam activates at L6 +- [ ] Dual video works at L7 +- [ ] TTS speaks at L8 +- [ ] Quad video displays at L9 +- [ ] Hypno spiral shows at L10 + +--- + +### Task 5: Library/Preference Integration (1-2 hours) + +Ensure checkpoints work: + +**At L1**: Show preference form +**At L5**: Show preference form + library stats +**At L10**: Show preference form + library stats + +**Testing Checklist**: +- [ ] L1 shows preferences +- [ ] L5 shows preferences and library +- [ ] L10 shows preferences and library +- [ ] Preferences affect content selection + +--- + +## 📏 Measurable Test Criteria + +After Phase 2, ALL of these must pass: + +### Level 1: +- [ ] Can start L1 +- [ ] Preference form appears +- [ ] Edge counter works +- [ ] Completing L1 unlocks L2 + +### Level 2: +- [ ] Rhythm pattern displays +- [ ] Library directory adds +- [ ] Completing L2 unlocks L3 + +### Level 3: +- [ ] Video plays +- [ ] Tagging UI works +- [ ] Tag at least 10 files +- [ ] Completing L3 unlocks L4 + +### Level 4: +- [ ] Video + rhythm work simultaneously +- [ ] Completing L4 unlocks L5 + +### Level 5 (Checkpoint): +- [ ] Preference form appears +- [ ] Library stats display +- [ ] Foundation Arc completes +- [ ] Completing L5 unlocks L6 + +### Level 6: +- [ ] Webcam enables +- [ ] Webcam feed displays +- [ ] Completing L6 unlocks L7 + +### Level 7: +- [ ] Dual video displays (main + PiP) +- [ ] PiP positions correctly +- [ ] Completing L7 unlocks L8 + +### Level 8: +- [ ] TTS speaks commands +- [ ] Voice is audible +- [ ] Completing L8 unlocks L9 + +### Level 9: +- [ ] Quad video grid displays +- [ ] All 4 videos play +- [ ] Completing L9 unlocks L10 + +### Level 10 (Checkpoint): +- [ ] Hypno spiral displays +- [ ] Spiral animates +- [ ] Preference form appears +- [ ] Feature Discovery Arc completes +- [ ] Completing L10 unlocks L11 + +### Overall: +- [ ] All levels playable +- [ ] No console errors +- [ ] Progress saves after each level +- [ ] Feature unlocks persist + +--- + +## 🎯 Success Criteria + +**Phase 2 Complete When:** +1. Levels 1-10 fully functional +2. Foundation + Feature Discovery arcs complete +3. All measurable tests pass +4. Checkpoints at L5 and L10 work +5. Feature unlocking progresses correctly +6. Can play L1 → L10 sequentially + +--- + +## 📂 Files Created/Modified + +### New Files: +- `src/data/modes/academyLevelData.js` + +### Modified Files: +- `src/features/tasks/interactiveTaskManager.js` +- `training-academy.html` +- `src/features/webcam/webcamManager.js` +- `src/features/video/videoPlayerManager.js` +- `src/features/tts/voiceManager.js` + +--- + +## 🚀 Next Phase + +After Phase 2: **Phase 3: Levels 11-20 Implementation** (Mind & Body + Advanced Training arcs) diff --git a/docs/training-game-redesign/PHASE-3.md b/docs/training-game-redesign/PHASE-3.md new file mode 100644 index 0000000..4e0b615 --- /dev/null +++ b/docs/training-game-redesign/PHASE-3.md @@ -0,0 +1,785 @@ +# Phase 3: Levels 11-20 Implementation + +**Priority**: MEDIUM-HIGH - Advanced features and complexity +**Estimated Effort**: 18-24 hours +**Status**: Not Started +**Dependencies**: Phase 2 (Levels 1-10) + +--- + +## 🎯 Phase Goals + +Implement levels 11-20, covering the **Mind & Body Arc** (L11-15) and **Advanced Training Arc** (L16-20). These levels introduce hypno overlays, captions, interruptions, popups, and complex multi-feature coordination. + +--- + +## 📋 What This Phase Delivers + +### Arcs Implemented: +1. **Mind & Body Arc (L11-15)**: Hypno overlays, captions, TTS+spiral combos, sensory overload +2. **Advanced Training Arc (L16-20)**: Interruptions, denial training, popup images, 90-minute marathon + +### Level-by-Level: +- **L11**: Mind Sync (75min) - Hypno + captions +- **L12**: Caption Conditioning (80min) - Dynamic captions based on preferences +- **L13**: Voice in the Spiral (85min) - TTS + hypno synchronized +- **L14**: Sensory Overload (90min) - Quad + hypno + TTS + captions +- **L15**: Mind & Body Checkpoint (100min) - Preference update + arc recap +- **L16**: Controlled Chaos (110min) - Interruptions unlock +- **L17**: The Denial Dance (120min) - Forced denial training +- **L18**: Popup Distraction (130min) - Random popup images +- **L19**: Total Immersion (140min) - All features combined +- **L20**: Ultimate Checkpoint (150min) - All features unlocked, preference update + +**End Result**: Full feature suite unlocked, players mastering complex multi-feature sessions. + +--- + +## 🏗️ Implementation Tasks + +### Task 1: Advanced Action Handlers (7-9 hours) + +**File to Update**: `src/features/tasks/interactiveTaskManager.js` + +Add handlers for L11-20 actions: + +#### New Action Types: + +**Hypno + Caption Combos (L11-14)**: +```javascript +{ + type: 'hypno-caption-combo', + params: { + hypnoDuration: 180, + captions: [ + { text: 'You are a good gooner', delay: 10 }, + { text: 'Edging is pleasure', delay: 30 } + ] + } +} + +{ + type: 'dynamic-captions', + params: { + duration: 300, + captionSource: 'preference-based', // generates based on user preferences + frequency: 15 // new caption every 15 seconds + } +} + +{ + type: 'tts-hypno-sync', + params: { + spiralDuration: 120, + ttsCommands: [ + { text: 'Watch the spiral...', delay: 10 }, + { text: 'Deeper...', delay: 60 } + ] + } +} + +{ + type: 'sensory-overload', + params: { + features: ['quad-video', 'hypno', 'tts', 'captions'], + duration: 300 + } +} +``` + +**Interruption System (L16)**: +```javascript +{ + type: 'enable-interruptions', + params: { + types: ['edge', 'pose', 'mantra'], + frequency: 'medium', // low/medium/high + randomize: true + } +} + +{ + type: 'interruption', + params: { + interruptionType: 'edge', // 'edge', 'pose', 'mantra', 'stop-stroking' + duration: 30, + instruction: 'STOP! Edge right now!' + } +} +``` + +**Denial Training (L17)**: +```javascript +{ + type: 'denial-training', + params: { + denialPeriods: [ + { duration: 120, instruction: 'No touching for 2 minutes' }, + { allowStroking: 60 }, + { duration: 180, instruction: 'Hands off again' } + ] + } +} + +{ + type: 'stop-stroking', + params: { + duration: 120, + showTimer: true + } +} +``` + +**Popup System (L18)**: +```javascript +{ + type: 'enable-popups', + params: { + frequency: 'medium', + sources: ['tasks', 'consequences'], // image folders + duration: 10, // seconds per popup + randomize: true + } +} + +{ + type: 'popup-image', + params: { + imagePath: '/images/tasks/edge.png', + duration: 10, + position: 'center' // or random + } +} +``` + +#### Handler Implementation: + +```javascript +class InteractiveTaskManager { + // ... existing handlers ... + + async handleHypnoCaptionCombo(action) { + // Start hypno spiral + // Schedule captions at specified delays + // Run both simultaneously + } + + async handleDynamicCaptions(action) { + // Get user preferences + // Generate captions based on themes + // Display new caption every N seconds + // Track caption history + } + + async handleTTSHypnoSync(action) { + // Start spiral + // Schedule TTS commands + // Synchronize timing + } + + async handleSensoryOverload(action) { + // Activate all specified features + // Quad video + hypno + TTS + captions + // Coordinate timing + } + + async handleEnableInterruptions(action) { + // Set up random interruption scheduler + // Based on frequency, schedule random interruptions + // Store interruption state + } + + async handleInterruption(action) { + // Pause current activities + // Show interruption overlay (STOP! EDGE!) + // Wait for user to complete + // Resume activities + } + + async handleDenialTraining(action) { + // Loop through denial periods + // Enforce "hands off" periods with timer + // Allow stroking periods + } + + async handleStopStroking(action) { + // Display "HANDS OFF" timer + // Count down duration + // Detect if user fails (optional) + } + + async handleEnablePopups(action) { + // Set up random popup scheduler + // Based on frequency, show random images + } + + async handlePopupImage(action) { + // Display image overlay + // Auto-hide after duration + } +} +``` + +**Testing Checklist**: +- [ ] Hypno + captions work simultaneously +- [ ] Dynamic captions generate from preferences +- [ ] TTS + hypno synchronize correctly +- [ ] Sensory overload coordinates all features +- [ ] Interruptions trigger randomly +- [ ] Denial periods enforce "hands off" +- [ ] Popups display at correct frequency +- [ ] All advanced handlers work without conflicts + +--- + +### Task 2: Caption System (4-5 hours) + +**File to Create**: `src/features/captions/captionManager.js` + +**Responsibilities**: +- Generate captions based on preferences +- Display captions with timing +- Track caption history +- Support manual and automatic captions + +**Data Structure**: +```javascript +const captionTemplates = { + edging: [ + "You are a good gooner", + "Edge for me", + "Stroke faster", + "Slower now..." + ], + sissy: [ + "You're such a sissy", + "Good girl", + "Embrace your feminine side" + ], + humiliation: [ + "You're addicted", + "You can't stop", + "This is what you are" + ], + worship: [ + "Worship this body", + "You live to serve", + "Obey" + ] + // ... more themes +}; +``` + +**Methods**: +```javascript +class CaptionManager { + generateCaption(themes) { + // Pick random template from enabled themes + } + + displayCaption(text, duration = 5) { + // Show caption overlay + // Auto-hide after duration + } + + startAutoCaptions(frequency, themes) { + // Generate and display captions every N seconds + } + + stopAutoCaptions() { + // Stop auto-caption loop + } +} +``` + +**UI Component**: +```html + +``` + +**Testing Checklist**: +- [ ] Captions generate from templates +- [ ] Captions respect preferences +- [ ] Auto-captions cycle correctly +- [ ] Manual captions display properly +- [ ] Caption overlay styled correctly + +--- + +### Task 3: Interruption System (3-4 hours) + +**File to Create**: `src/features/interruptions/interruptionManager.js` + +**Responsibilities**: +- Schedule random interruptions +- Display interruption overlays +- Pause/resume current activities +- Track interruption compliance + +**Interruption Types**: +- **Edge**: "STOP! Edge right now!" +- **Pose**: "Hold this pose for 30 seconds" +- **Mantra**: "Repeat: I am a good gooner" +- **Stop Stroking**: "Hands off for 2 minutes" + +**Methods**: +```javascript +class InterruptionManager { + enable(frequency = 'medium') { + // Schedule random interruptions + // frequency: low (5-10min), medium (3-5min), high (1-3min) + } + + disable() { + // Stop interruption scheduler + } + + triggerInterruption(type, params) { + // Pause current activities + // Show interruption overlay + // Execute interruption + // Resume activities + } + + scheduleNext() { + // Schedule next random interruption + } +} +``` + +**UI Component**: +```html + +``` + +**Testing Checklist**: +- [ ] Interruptions trigger at correct frequency +- [ ] Interruption overlay displays +- [ ] Current activities pause +- [ ] Activities resume after interruption +- [ ] All interruption types work + +--- + +### Task 4: Popup Image System (2-3 hours) + +**File to Update**: `src/features/images/popupImageManager.js` + +**Enhancements**: +- Random scheduling based on frequency +- Tag-based image selection +- Auto-hide after duration + +**Methods**: +```javascript +class PopupImageManager { + enableAutoPopups(frequency, tags) { + // Schedule random popups + // Filter images by tags + } + + disableAutoPopups() { + // Stop popup scheduler + } + + showPopup(imagePath, duration = 10) { + // Display popup + // Auto-hide after duration + } +} +``` + +**Testing Checklist**: +- [ ] Popups trigger at correct frequency +- [ ] Images filtered by tags +- [ ] Popups auto-hide +- [ ] Multiple popups don't overlap + +--- + +### Task 5: Level Data for L11-20 (3-4 hours) + +**File to Update**: `src/data/modes/academyLevelData.js` + +Add levels 11-20: + +```javascript +const academyLevels = { + // ... L1-10 ... + + 11: { + name: "Mind Sync", + arc: "Mind & Body", + duration: 4500, // 75 minutes + requirements: { + minLevel: 11, + completedLevels: [10], + featuresUnlocked: ['hypno'] + }, + unlocks: { + level: 12, + features: ['captions'] + }, + sessionStructure: { + main: [ + { type: 'hypno-caption-combo', params: { + hypnoDuration: 180, + captions: [ + { text: 'You are a good gooner', delay: 10 }, + { text: 'Edging is your purpose', delay: 60 } + ] + }}, + { type: 'quad-video' }, + { type: 'edge', params: { count: 75 } } + ] + } + }, + + 12: { + name: "Caption Conditioning", + arc: "Mind & Body", + duration: 4800, // 80 minutes + requirements: { + minLevel: 12, + completedLevels: [11], + featuresUnlocked: ['captions'] + }, + unlocks: { + level: 13 + }, + sessionStructure: { + main: [ + { type: 'dynamic-captions', params: { + duration: 4800, + captionSource: 'preference-based', + frequency: 20 + }}, + { type: 'video-start' }, + { type: 'edge', params: { count: 80 } } + ] + } + }, + + 13: { + name: "Voice in the Spiral", + arc: "Mind & Body", + duration: 5100, // 85 minutes + requirements: { + minLevel: 13, + completedLevels: [12] + }, + unlocks: { + level: 14 + }, + sessionStructure: { + main: [ + { type: 'tts-hypno-sync', params: { + spiralDuration: 300, + ttsCommands: [ + { text: 'Watch the spiral...', delay: 10 }, + { text: 'Deeper and deeper...', delay: 120 }, + { text: 'You are under my control...', delay: 240 } + ] + }}, + { type: 'edge', params: { count: 85 } } + ] + } + }, + + 14: { + name: "Sensory Overload", + arc: "Mind & Body", + duration: 5400, // 90 minutes + requirements: { + minLevel: 14, + completedLevels: [13] + }, + unlocks: { + level: 15 + }, + sessionStructure: { + main: [ + { type: 'sensory-overload', params: { + features: ['quad-video', 'hypno', 'tts', 'captions'], + duration: 5400 + }}, + { type: 'edge', params: { count: 90 } } + ] + } + }, + + 15: { + name: "Mind & Body Checkpoint", + arc: "Mind & Body", + duration: 6000, // 100 minutes + isCheckpoint: true, + requirements: { + minLevel: 15, + completedLevels: [14] + }, + unlocks: { + level: 16, + features: [], + arcsCompleted: ['Mind & Body'] + }, + sessionStructure: { + warmup: [ + { type: 'show-preferences', reason: 'checkpoint' } + ], + main: [ + { type: 'sensory-overload', params: { features: ['quad-video', 'hypno', 'tts', 'captions'], duration: 5400 } }, + { type: 'edge', params: { count: 100 } } + ], + cooldown: [ + { type: 'show-arc-complete', arc: 'Mind & Body' } + ] + } + }, + + 16: { + name: "Controlled Chaos", + arc: "Advanced Training", + duration: 6600, // 110 minutes + requirements: { + minLevel: 16, + completedLevels: [15] + }, + unlocks: { + level: 17, + features: ['interruptions'] + }, + sessionStructure: { + main: [ + { type: 'enable-interruptions', params: { types: ['edge', 'pose'], frequency: 'medium' } }, + { type: 'quad-video' }, + { type: 'edge', params: { count: 110 } } + ] + }, + failureConditions: { + cumming: true, + abandoningSession: true, + closingFeatures: ['quad-video'], + ignoringInterruptions: true + } + }, + + 17: { + name: "The Denial Dance", + arc: "Advanced Training", + duration: 7200, // 120 minutes + requirements: { + minLevel: 17, + completedLevels: [16], + featuresUnlocked: ['interruptions'] + }, + unlocks: { + level: 18 + }, + sessionStructure: { + main: [ + { type: 'denial-training', params: { + denialPeriods: [ + { duration: 300, instruction: 'Hands off for 5 minutes' }, + { allowStroking: 120 }, + { duration: 600, instruction: 'Hands off for 10 minutes' } + ] + }}, + { type: 'edge', params: { count: 120 } } + ] + } + }, + + 18: { + name: "Popup Distraction", + arc: "Advanced Training", + duration: 7800, // 130 minutes + requirements: { + minLevel: 18, + completedLevels: [17] + }, + unlocks: { + level: 19, + features: ['popups'] + }, + sessionStructure: { + main: [ + { type: 'enable-popups', params: { frequency: 'medium', sources: ['tasks', 'consequences'] } }, + { type: 'quad-video' }, + { type: 'edge', params: { count: 130 } } + ] + } + }, + + 19: { + name: "Total Immersion", + arc: "Advanced Training", + duration: 8400, // 140 minutes + requirements: { + minLevel: 19, + completedLevels: [18], + featuresUnlocked: ['popups'] + }, + unlocks: { + level: 20 + }, + sessionStructure: { + main: [ + { type: 'enable-interruptions', params: { frequency: 'high' } }, + { type: 'enable-popups', params: { frequency: 'high' } }, + { type: 'sensory-overload', params: { features: ['quad-video', 'hypno', 'tts', 'captions'] } }, + { type: 'edge', params: { count: 140 } } + ] + } + }, + + 20: { + name: "Ultimate Checkpoint", + arc: "Advanced Training", + duration: 9000, // 150 minutes + isCheckpoint: true, + requirements: { + minLevel: 20, + completedLevels: [19] + }, + unlocks: { + level: 21, + features: [], // All features now unlocked + arcsCompleted: ['Advanced Training'], + durationTiers: ['Quick', 'Standard', 'Extended'] // Marathon at L25 + }, + sessionStructure: { + warmup: [ + { type: 'show-preferences', reason: 'checkpoint' } + ], + main: [ + { type: 'enable-interruptions', params: { frequency: 'high' } }, + { type: 'enable-popups', params: { frequency: 'high' } }, + { type: 'sensory-overload', params: { features: ['quad-video', 'hypno', 'tts', 'captions'] } }, + { type: 'edge', params: { count: 150 } } + ], + cooldown: [ + { type: 'show-arc-complete', arc: 'Advanced Training' }, + { type: 'show-message', text: 'All features unlocked! Duration tiers available.' } + ] + } + } +}; +``` + +**Testing Checklist**: +- [ ] All L11-20 defined +- [ ] Requirements check correctly +- [ ] Feature unlocks work +- [ ] Checkpoints at L15 and L20 trigger + +--- + +## 📏 Measurable Test Criteria + +After Phase 3, ALL of these must pass: + +### Level 11: +- [ ] Hypno spiral displays +- [ ] Captions appear with spiral +- [ ] Quad video plays +- [ ] Completing L11 unlocks L12 + +### Level 12: +- [ ] Dynamic captions generate +- [ ] Captions respect preferences +- [ ] Captions cycle every 20 seconds +- [ ] Completing L12 unlocks L13 + +### Level 13: +- [ ] TTS + hypno synchronize +- [ ] Voice commands match spiral timing +- [ ] Completing L13 unlocks L14 + +### Level 14: +- [ ] All features activate (quad + hypno + TTS + captions) +- [ ] No feature conflicts +- [ ] Completing L14 unlocks L15 + +### Level 15 (Checkpoint): +- [ ] Preference form appears +- [ ] Library stats display +- [ ] Mind & Body Arc completes +- [ ] Completing L15 unlocks L16 + +### Level 16: +- [ ] Interruptions enable +- [ ] Interruptions trigger randomly +- [ ] Interruption overlay displays +- [ ] Activities pause/resume +- [ ] Completing L16 unlocks L17 + +### Level 17: +- [ ] Denial periods enforce "hands off" +- [ ] Timer displays for denial periods +- [ ] Completing L17 unlocks L18 + +### Level 18: +- [ ] Popups enable +- [ ] Popups display randomly +- [ ] Images filtered correctly +- [ ] Completing L18 unlocks L19 + +### Level 19: +- [ ] All features coordinate (interruptions + popups + sensory overload) +- [ ] High frequency works without conflicts +- [ ] Completing L19 unlocks L20 + +### Level 20 (Checkpoint): +- [ ] Preference form appears +- [ ] Advanced Training Arc completes +- [ ] Duration tiers unlock message displays +- [ ] All features confirmed unlocked +- [ ] Completing L20 unlocks L21 + +### Overall: +- [ ] All levels L11-20 playable +- [ ] No console errors +- [ ] Progress saves after each level +- [ ] Feature unlocks persist +- [ ] Can play L11 → L20 sequentially + +--- + +## 🎯 Success Criteria + +**Phase 3 Complete When:** +1. Levels 11-20 fully functional +2. Mind & Body + Advanced Training arcs complete +3. All measurable tests pass +4. Caption system working +5. Interruption system working +6. Popup system working +7. All features coordinate without conflicts +8. Checkpoints at L15 and L20 work + +--- + +## 📂 Files Created/Modified + +### New Files: +- `src/features/captions/captionManager.js` +- `src/features/interruptions/interruptionManager.js` + +### Modified Files: +- `src/features/tasks/interactiveTaskManager.js` +- `src/features/images/popupImageManager.js` +- `src/data/modes/academyLevelData.js` +- `training-academy.html` + +--- + +## 🚀 Next Phase + +After Phase 3: **Phase 4: Levels 21-25 Path Specialization** diff --git a/docs/training-game-redesign/PHASE-4.md b/docs/training-game-redesign/PHASE-4.md new file mode 100644 index 0000000..aa71cd8 --- /dev/null +++ b/docs/training-game-redesign/PHASE-4.md @@ -0,0 +1,797 @@ +# Phase 4: Levels 21-25 Path Specialization + +**Priority**: MEDIUM - Path differentiation and specialization +**Estimated Effort**: 20-26 hours +**Status**: Not Started +**Dependencies**: Phase 3 (Levels 11-20) + +--- + +## 🎯 Phase Goals + +Implement levels 21-25, covering the **Path Specialization Arc**. At Level 21, players choose one of 6 specialized paths based on their preferences and goals. Levels 22-25 provide path-specific scenarios and challenges. + +--- + +## 📋 What This Phase Delivers + +### Arc Implemented: +**Path Specialization Arc (L21-25)**: Path selection + 4 path-specific levels + +### The 6 Paths: +1. **Endurance Path**: Stamina building, marathon sessions, long-duration challenges +2. **Denial Path**: Extended denial, edging without release, frustration training +3. **Humiliation Path**: Degradation scenarios, humiliation tasks, ego dissolution +4. **Obedience Path**: Command following, submission training, control surrender +5. **Sensitivity Path**: Heightened arousal, minimal touch, extreme sensitivity +6. **Multi-Sensory Path**: All features maxed, overwhelming stimulation, sensory mastery + +### Level-by-Level: +- **L21**: Path Selection (165min) - Questionnaire + path choice +- **L22**: Path Level 1 (180min) - Introduction to chosen path +- **L23**: Path Level 2 (195min) - Intermediate path training +- **L24**: Path Level 3 (210min) - Advanced path challenges +- **L25**: Path Mastery Checkpoint (225min) - Path graduation + preference update + +**End Result**: Personalized experience based on user's path choice, preparing for Ultimate Mastery arc. + +--- + +## 🏗️ Implementation Tasks + +### Task 1: Path Selection System (5-6 hours) + +**File to Create**: `src/features/academy/pathSelector.js` + +**Responsibilities**: +- Display path selection questionnaire +- Calculate recommended path based on answers +- Allow manual path override +- Save selected path +- Generate path-specific content + +**Questionnaire Questions**: +```javascript +const pathQuestions = [ + { + id: 1, + question: "What aspect of gooning excites you most?", + answers: [ + { text: "Going for hours without stopping", path: "Endurance", weight: 3 }, + { text: "Being denied release", path: "Denial", weight: 3 }, + { text: "Being degraded and humiliated", path: "Humiliation", weight: 3 }, + { text: "Following commands obediently", path: "Obedience", weight: 3 }, + { text: "Increasing my sensitivity", path: "Sensitivity", weight: 3 }, + { text: "Overwhelming my senses", path: "Multi-Sensory", weight: 3 } + ] + }, + { + id: 2, + question: "How do you prefer to edge?", + answers: [ + { text: "Slow and steady for maximum duration", path: "Endurance", weight: 2 }, + { text: "Right to the edge without going over", path: "Denial", weight: 2 }, + { text: "While being verbally degraded", path: "Humiliation", weight: 2 }, + { text: "Only when commanded", path: "Obedience", weight: 2 }, + { text: "With minimal touch", path: "Sensitivity", weight: 2 }, + { text: "With all features active", path: "Multi-Sensory", weight: 2 } + ] + }, + { + id: 3, + question: "What is your ultimate gooning goal?", + answers: [ + { text: "Goon for 5+ hours straight", path: "Endurance", weight: 3 }, + { text: "Edge for days without cumming", path: "Denial", weight: 3 }, + { text: "Embrace total humiliation", path: "Humiliation", weight: 3 }, + { text: "Become perfectly obedient", path: "Obedience", weight: 3 }, + { text: "Cum from minimal stimulation", path: "Sensitivity", weight: 3 }, + { text: "Master sensory overload", path: "Multi-Sensory", weight: 3 } + ] + }, + { + id: 4, + question: "Which feature do you enjoy most?", + answers: [ + { text: "Long video marathons", path: "Endurance", weight: 1 }, + { text: "Denial and stop-stroking commands", path: "Denial", weight: 1 }, + { text: "Humiliating captions and tasks", path: "Humiliation", weight: 1 }, + { text: "TTS commands and instructions", path: "Obedience", weight: 1 }, + { text: "Hypno spirals and edge control", path: "Sensitivity", weight: 1 }, + { text: "Everything at once", path: "Multi-Sensory", weight: 1 } + ] + }, + { + id: 5, + question: "How intense should your training be?", + answers: [ + { text: "Moderate but long-lasting", path: "Endurance", weight: 2 }, + { text: "Intensely frustrating", path: "Denial", weight: 2 }, + { text: "Psychologically challenging", path: "Humiliation", weight: 2 }, + { text: "Strictly controlled", path: "Obedience", weight: 2 }, + { text: "Physically overwhelming", path: "Sensitivity", weight: 2 }, + { text: "Maximum intensity across all dimensions", path: "Multi-Sensory", weight: 2 } + ] + } +]; +``` + +**Path Calculation**: +```javascript +class PathSelector { + calculateRecommendedPath(answers) { + // Sum weights for each path + // Return path with highest score + } + + showPathSelection(recommendedPath) { + // Display questionnaire results + // Show recommended path with description + // Allow user to override choice + // Return selected path + } + + savePath(path) { + // Save to academyProgress.selectedPath + } + + getPathDescription(path) { + // Return detailed description of path + } +} +``` + +**Path Descriptions**: +```javascript +const pathDescriptions = { + Endurance: { + name: "Endurance Path", + tagline: "Master of marathons", + description: "Build stamina for ultra-long sessions. Train to goon for hours without breaks.", + focus: "Duration, stamina, marathon sessions", + graduation: "5-hour session with minimal breaks" + }, + Denial: { + name: "Denial Path", + tagline: "Master of frustration", + description: "Learn to edge endlessly without release. Embrace permanent denial.", + focus: "Denial periods, edging without cumming, frustration tolerance", + graduation: "4-hour denial session with 100+ edges" + }, + Humiliation: { + name: "Humiliation Path", + tagline: "Master of degradation", + description: "Embrace humiliation and ego dissolution. Become the perfect degraded gooner.", + focus: "Humiliating tasks, degrading captions, ego death", + graduation: "Humiliation gauntlet with extreme tasks" + }, + Obedience: { + name: "Obedience Path", + tagline: "Master of submission", + description: "Perfect command following. Learn total obedience and control surrender.", + focus: "TTS commands, instant obedience, submission", + graduation: "Perfect obedience test with complex commands" + }, + Sensitivity: { + name: "Sensitivity Path", + tagline: "Master of sensation", + description: "Heighten your sensitivity to extreme levels. Minimal touch, maximum pleasure.", + focus: "Sensitivity training, minimal stimulation, edge control", + graduation: "Hands-free or minimal-touch edge marathon" + }, + MultiSensory: { + name: "Multi-Sensory Path", + tagline: "Master of everything", + description: "All features, maximum intensity. Become a master of sensory overload.", + focus: "All features combined, maximum complexity, total immersion", + graduation: "Ultimate sensory overload challenge" + } +}; +``` + +**Testing Checklist**: +- [ ] Questionnaire displays +- [ ] Answers calculate recommended path +- [ ] Path descriptions display +- [ ] Can override recommendation +- [ ] Selected path saves + +--- + +### Task 2: Path-Specific Action Handlers (6-8 hours) + +**File to Update**: `src/features/tasks/interactiveTaskManager.js` + +Add handlers for path-specific actions: + +#### Endurance Path Actions: +```javascript +{ + type: 'marathon-warmup', + params: { + duration: 600, // 10-minute warmup + instruction: 'Prepare your body and mind for the long haul' + } +} + +{ + type: 'stamina-building', + params: { + edgeCycles: 5, + cycleLength: 300, // 5-minute cycles + intensity: 'moderate' + } +} + +{ + type: 'endurance-test', + params: { + duration: 3600, // 1-hour test + minEdges: 30, + breaks: 'none' + } +} +``` + +#### Denial Path Actions: +```javascript +{ + type: 'extended-denial', + params: { + denialDuration: 1800, // 30-minute denial + allowedTouching: 'none', + showTimer: true + } +} + +{ + type: 'frustration-building', + params: { + edgesToBrink: 20, + forcedStops: 5 + } +} + +{ + type: 'denial-oath', + params: { + oath: 'I will not cum. I am a denied gooner.', + repetitions: 10 + } +} +``` + +#### Humiliation Path Actions: +```javascript +{ + type: 'humiliation-task', + params: { + task: 'Write "I am a pathetic gooner" 10 times', + verification: 'photo' // optional + } +} + +{ + type: 'degrading-mantra', + params: { + mantra: 'I am addicted. I am weak. I am a gooner.', + duration: 300, + tts: true + } +} + +{ + type: 'ego-dissolution', + params: { + captions: 'degrading', + hypno: true, + duration: 600 + } +} +``` + +#### Obedience Path Actions: +```javascript +{ + type: 'command-drill', + params: { + commands: [ + { command: 'Edge now', delay: 10 }, + { command: 'Stop', delay: 5 }, + { command: 'Edge again', delay: 10 } + ] + } +} + +{ + type: 'instant-obedience', + params: { + randomCommands: true, + commandFrequency: 30, // every 30 seconds + duration: 600 + } +} + +{ + type: 'obedience-oath', + params: { + oath: 'I obey. I submit. I am controlled.', + repetitions: 10 + } +} +``` + +#### Sensitivity Path Actions: +```javascript +{ + type: 'sensitivity-training', + params: { + touchIntensity: 'minimal', + edges: 20, + instruction: 'Use only your fingertips' + } +} + +{ + type: 'slow-edge', + params: { + duration: 600, // 10-minute slow edge + maxStrokes: 100 + } +} + +{ + type: 'hands-free-attempt', + params: { + duration: 300, + allowedStimulation: 'visual-only' + } +} +``` + +#### Multi-Sensory Path Actions: +```javascript +{ + type: 'total-overload', + params: { + features: ['quad-video', 'hypno', 'tts', 'captions', 'interruptions', 'popups', 'webcam'], + duration: 900, + intensity: 'maximum' + } +} + +{ + type: 'feature-cascade', + params: { + startWith: ['video'], + addEvery: 60, // add feature every 60 seconds + features: ['tts', 'hypno', 'captions', 'quad-video', 'popups', 'interruptions'] + } +} + +{ + type: 'sensory-mastery', + params: { + allFeatures: true, + complexTasks: true, + duration: 1200 + } +} +``` + +**Handler Implementation**: +```javascript +class InteractiveTaskManager { + // ... existing handlers ... + + // Endurance handlers + async handleMarathonWarmup(action) { /* Warmup routine */ } + async handleStaminaBuilding(action) { /* Edge cycles */ } + async handleEnduranceTest(action) { /* Long duration test */ } + + // Denial handlers + async handleExtendedDenial(action) { /* Long denial period */ } + async handleFrustrationBuilding(action) { /* Edge to brink repeatedly */ } + async handleDenialOath(action) { /* Repeat oath */ } + + // Humiliation handlers + async handleHumiliationTask(action) { /* Display and verify task */ } + async handleDegradingMantra(action) { /* TTS mantra loop */ } + async handleEgoDissolution(action) { /* Hypno + degrading captions */ } + + // Obedience handlers + async handleCommandDrill(action) { /* Sequence of commands */ } + async handleInstantObedience(action) { /* Random rapid commands */ } + async handleObedienceOath(action) { /* Repeat oath */ } + + // Sensitivity handlers + async handleSensitivityTraining(action) { /* Minimal touch edges */ } + async handleSlowEdge(action) { /* Slow, controlled edge */ } + async handleHandsFreeAttempt(action) { /* No touch challenge */ } + + // Multi-Sensory handlers + async handleTotalOverload(action) { /* Activate all features */ } + async handleFeatureCascade(action) { /* Add features progressively */ } + async handleSensoryMastery(action) { /* Ultimate challenge */ } +} +``` + +**Testing Checklist**: +- [ ] All 6 paths have unique actions +- [ ] Path-specific handlers work correctly +- [ ] Actions respect path focus +- [ ] No conflicts between path actions + +--- + +### Task 3: Path-Specific Level Data (4-5 hours) + +**File to Update**: `src/data/modes/academyLevelData.js` + +Add levels 21-25 with path variations: + +```javascript +const academyLevels = { + // ... L1-20 ... + + 21: { + name: "Path Selection", + arc: "Path Specialization", + duration: 9900, // 165 minutes + requirements: { + minLevel: 21, + completedLevels: [20] + }, + unlocks: { + level: 22 + }, + sessionStructure: { + warmup: [ + { type: 'show-path-questionnaire' } + ], + main: [ + { type: 'quad-video' }, + { type: 'edge', params: { count: 165 } } + ], + cooldown: [ + { type: 'show-path-results' }, + { type: 'save-path-selection' } + ] + } + }, + + 22: { + name: "Path Level 1", + arc: "Path Specialization", + duration: 10800, // 180 minutes + requirements: { + minLevel: 22, + completedLevels: [21], + pathSelected: true + }, + unlocks: { + level: 23 + }, + sessionStructure: { + // Different structure per path + Endurance: { + main: [ + { type: 'marathon-warmup', params: { duration: 600 } }, + { type: 'stamina-building', params: { edgeCycles: 5, cycleLength: 300 } }, + { type: 'edge', params: { count: 100 } } + ] + }, + Denial: { + main: [ + { type: 'extended-denial', params: { denialDuration: 1800 } }, + { type: 'frustration-building', params: { edgesToBrink: 30 } }, + { type: 'denial-oath', params: { repetitions: 10 } } + ] + }, + Humiliation: { + main: [ + { type: 'humiliation-task', params: { task: 'Write degrading affirmations' } }, + { type: 'degrading-mantra', params: { duration: 600, tts: true } }, + { type: 'edge', params: { count: 80 } } + ] + }, + Obedience: { + main: [ + { type: 'command-drill', params: { commands: [...] } }, + { type: 'instant-obedience', params: { duration: 900 } }, + { type: 'obedience-oath', params: { repetitions: 10 } } + ] + }, + Sensitivity: { + main: [ + { type: 'sensitivity-training', params: { edges: 50 } }, + { type: 'slow-edge', params: { duration: 1200 } }, + { type: 'hands-free-attempt', params: { duration: 300 } } + ] + }, + MultiSensory: { + main: [ + { type: 'feature-cascade', params: { startWith: ['video'], addEvery: 120 } }, + { type: 'total-overload', params: { duration: 1800 } } + ] + } + } + }, + + 23: { + name: "Path Level 2", + arc: "Path Specialization", + duration: 11700, // 195 minutes + requirements: { + minLevel: 23, + completedLevels: [22] + }, + unlocks: { + level: 24 + }, + sessionStructure: { + // Intermediate path training (more intense) + // Similar structure to L22 but harder + } + }, + + 24: { + name: "Path Level 3", + arc: "Path Specialization", + duration: 12600, // 210 minutes + requirements: { + minLevel: 24, + completedLevels: [23] + }, + unlocks: { + level: 25 + }, + sessionStructure: { + // Advanced path challenges + // Similar structure to L23 but hardest + } + }, + + 25: { + name: "Path Mastery", + arc: "Path Specialization", + duration: 13500, // 225 minutes + isCheckpoint: true, + requirements: { + minLevel: 25, + completedLevels: [24] + }, + unlocks: { + level: 26, + arcsCompleted: ['Path Specialization'], + durationTiers: ['Marathon'] // Unlock Marathon tier (15x) + }, + sessionStructure: { + warmup: [ + { type: 'show-preferences', reason: 'checkpoint' } + ], + main: { + // Path graduation challenge + // Hardest test for each path + Endurance: [ + { type: 'endurance-test', params: { duration: 7200, minEdges: 100 } } + ], + Denial: [ + { type: 'extended-denial', params: { denialDuration: 3600 } }, + { type: 'frustration-building', params: { edgesToBrink: 100 } } + ], + Humiliation: [ + { type: 'ego-dissolution', params: { duration: 3600 } }, + { type: 'humiliation-task', params: { task: 'Ultimate humiliation gauntlet' } } + ], + Obedience: [ + { type: 'instant-obedience', params: { duration: 3600, commandFrequency: 15 } } + ], + Sensitivity: [ + { type: 'hands-free-attempt', params: { duration: 1800 } }, + { type: 'slow-edge', params: { duration: 1800, maxStrokes: 50 } } + ], + MultiSensory: [ + { type: 'sensory-mastery', params: { duration: 3600, allFeatures: true } } + ] + }, + cooldown: [ + { type: 'show-arc-complete', arc: 'Path Specialization' }, + { type: 'show-path-graduation', path: 'selected' } + ] + } + } +}; +``` + +**Testing Checklist**: +- [ ] L21 questionnaire works +- [ ] Path selection saves +- [ ] L22-24 load correct path structure +- [ ] L25 graduation challenge matches path +- [ ] Marathon tier unlocks at L25 + +--- + +### Task 4: Path Data Management (2-3 hours) + +**File to Create**: `src/data/academy/pathData.js` + +**Path Definitions**: +```javascript +export const paths = { + Endurance: { + // ... full path definition ... + }, + // ... other 5 paths ... +}; + +export const pathQuestionnaire = [ /* questions */ ]; +``` + +**File to Update**: `src/core/gameDataManager.js` + +Add `selectedPath` to `academyProgress`: +```javascript +academyProgress: { + // ... existing fields ... + selectedPath: null, // 'Endurance', 'Denial', etc. + pathQuestionnaireAnswers: [], + pathProgress: { + level22Complete: false, + level23Complete: false, + level24Complete: false, + level25Complete: false + } +} +``` + +**Testing Checklist**: +- [ ] Path data loads correctly +- [ ] Selected path persists +- [ ] Path progress tracks + +--- + +### Task 5: UI for Path Selection (3-4 hours) + +**File to Update**: `training-academy.html` + +Add path selection UI: + +```html + + + + + + + + +``` + +**Testing Checklist**: +- [ ] Questionnaire renders +- [ ] Results display correctly +- [ ] All 6 paths selectable +- [ ] Graduation modal displays + +--- + +## 📏 Measurable Test Criteria + +After Phase 4, ALL of these must pass: + +### Level 21 (Path Selection): +- [ ] Questionnaire displays with all 5 questions +- [ ] Can answer all questions +- [ ] Recommended path calculates correctly +- [ ] Path descriptions display +- [ ] Can override recommendation +- [ ] Selected path saves +- [ ] Completing L21 unlocks L22 + +### Level 22 (Path Level 1): +- [ ] Correct path structure loads +- [ ] Endurance path: Marathon warmup + stamina building work +- [ ] Denial path: Extended denial + frustration work +- [ ] Humiliation path: Tasks + degrading mantras work +- [ ] Obedience path: Commands + instant obedience work +- [ ] Sensitivity path: Sensitivity training + slow edges work +- [ ] Multi-Sensory path: Feature cascade + total overload work +- [ ] Completing L22 unlocks L23 + +### Level 23 (Path Level 2): +- [ ] Intermediate difficulty loads +- [ ] Path-specific content works +- [ ] Completing L23 unlocks L24 + +### Level 24 (Path Level 3): +- [ ] Advanced difficulty loads +- [ ] Path-specific content works +- [ ] Completing L24 unlocks L25 + +### Level 25 (Path Mastery): +- [ ] Preference form appears +- [ ] Path graduation challenge loads +- [ ] Endurance: 2-hour test works +- [ ] Denial: 1-hour denial + 100 edges work +- [ ] Humiliation: Ego dissolution + gauntlet work +- [ ] Obedience: 1-hour instant obedience works +- [ ] Sensitivity: Hands-free + slow edge work +- [ ] Multi-Sensory: Ultimate overload works +- [ ] Path graduation modal displays +- [ ] Marathon tier unlocks +- [ ] Path Specialization Arc completes +- [ ] Completing L25 unlocks L26 + +### Overall: +- [ ] All 6 paths functional +- [ ] Path selection persists +- [ ] No console errors +- [ ] Can complete L21 → L25 for any path +- [ ] Marathon tier confirmed unlocked + +--- + +## 🎯 Success Criteria + +**Phase 4 Complete When:** +1. Levels 21-25 fully functional +2. All 6 paths implemented +3. Path selection system works +4. All path-specific actions functional +5. All measurable tests pass +6. Path graduation displays correctly +7. Marathon tier unlocks at L25 + +--- + +## 📂 Files Created/Modified + +### New Files: +- `src/features/academy/pathSelector.js` +- `src/data/academy/pathData.js` + +### Modified Files: +- `src/features/tasks/interactiveTaskManager.js` +- `src/data/modes/academyLevelData.js` +- `src/core/gameDataManager.js` +- `training-academy.html` + +--- + +## 🚀 Next Phase + +After Phase 4: **Phase 5: Levels 26-30 + Graduation** (Ultimate Mastery arc) diff --git a/docs/training-game-redesign/PHASE-5.md b/docs/training-game-redesign/PHASE-5.md new file mode 100644 index 0000000..c34f67d --- /dev/null +++ b/docs/training-game-redesign/PHASE-5.md @@ -0,0 +1,693 @@ +# Phase 5: Levels 26-30 + Graduation + +**Priority**: MEDIUM - Campaign finale and graduation +**Estimated Effort**: 16-22 hours +**Status**: Not Started +**Dependencies**: Phase 4 (Levels 21-25) + +--- + +## 🎯 Phase Goals + +Implement levels 26-30, covering the **Ultimate Mastery Arc**. These are the final five levels of The Academy, culminating in the epic Level 30 graduation ceremony. Implement progressive intensity scaling, dynamic difficulty, and the graduation system. + +--- + +## 📋 What This Phase Delivers + +### Arc Implemented: +**Ultimate Mastery Arc (L26-30)**: Final challenges leading to graduation + +### Level-by-Level: +- **L26**: Ultimate Test I (240min / 4 hours) - Intensity Stage 1 +- **L27**: Ultimate Test II (255min / 4.25 hours) - Intensity Stage 2 +- **L28**: Ultimate Test III (270min / 4.5 hours) - Intensity Stage 3 +- **L29**: Ultimate Test IV (285min / 4.75 hours) - Intensity Stage 4 +- **L30**: Graduation (300min / 5 hours) - Final exam + ceremony + +### New Systems: +1. **Progressive Intensity System**: 4 stages (Moderate → Challenging → Intense → Extreme) +2. **Dynamic Difficulty Adjustment**: Adapts to user's path and preferences +3. **Graduation Ceremony**: Oath, certificate, stats report, photo gallery, library report +4. **Freeplay Mode**: Unlocked after graduation +5. **Ascended Mode**: Ultra-hard post-graduation mode + +**End Result**: Complete campaign with satisfying conclusion and post-game content. + +--- + +## 🏗️ Implementation Tasks + +### Task 1: Progressive Intensity System (5-6 hours) + +**File to Create**: `src/features/academy/intensityManager.js` + +**Responsibilities**: +- Calculate intensity based on level (26-30) +- Adjust feature frequency/complexity +- Generate intensity-scaled tasks +- Track intensity progression + +**Intensity Stages**: +```javascript +const intensityStages = { + 1: { + level: 26, + name: "Moderate", + description: "Warm up for the ultimate tests", + multipliers: { + edgeCount: 1.0, + interruptionFrequency: 1.0, + popupFrequency: 1.0, + denialDuration: 1.0, + featureCount: 4 // max 4 features at once + } + }, + 2: { + level: 27, + name: "Challenging", + description: "Ramping up the pressure", + multipliers: { + edgeCount: 1.2, + interruptionFrequency: 1.3, + popupFrequency: 1.3, + denialDuration: 1.2, + featureCount: 5 + } + }, + 3: { + level: 28, + name: "Intense", + description: "Testing your limits", + multipliers: { + edgeCount: 1.4, + interruptionFrequency: 1.6, + popupFrequency: 1.6, + denialDuration: 1.4, + featureCount: 6 + } + }, + 4: { + level: 29, + name: "Extreme", + description: "Maximum challenge before graduation", + multipliers: { + edgeCount: 1.6, + interruptionFrequency: 2.0, + popupFrequency: 2.0, + denialDuration: 1.6, + featureCount: 7 // all features + } + } +}; +``` + +**Methods**: +```javascript +class IntensityManager { + getIntensityStage(level) { + // Return intensity config for level 26-30 + } + + scaleAction(action, intensityStage) { + // Apply multipliers to action params + // e.g., edge count, interruption frequency + } + + generateIntensifiedSession(level, baseTasks) { + // Take base task list + // Apply intensity scaling + // Return intensified task list + } + + calculateDifficulty(level, path, preferences) { + // Combine level, path focus, and preferences + // Return difficulty score + } +} +``` + +**Testing Checklist**: +- [ ] Intensity stages defined +- [ ] Multipliers apply correctly +- [ ] Actions scale with intensity +- [ ] Difficulty calculation works + +--- + +### Task 2: Dynamic Difficulty Adjustment (3-4 hours) + +**File to Update**: `src/features/academy/intensityManager.js` + +**Responsibilities**: +- Adjust difficulty based on path +- Respect user preferences +- Generate path-specific challenges for L26-30 + +**Path-Specific Adjustments**: +```javascript +const pathIntensityAdjustments = { + Endurance: { + focus: 'duration', + adjustments: { + // Longer sessions, more edges + edgeCount: +20, + breakDuration: -30, // shorter breaks + sessionPacing: 'steady' + } + }, + Denial: { + focus: 'frustration', + adjustments: { + denialDuration: +300, // +5 minutes + edgesToBrink: +10, + releaseProhibited: true + } + }, + Humiliation: { + focus: 'psychological', + adjustments: { + degradingCaptions: true, + humiliationTasks: +5, + egoReduction: 'maximum' + } + }, + Obedience: { + focus: 'control', + adjustments: { + commandFrequency: +10, // more commands + instantCompliance: true, + complexCommands: true + } + }, + Sensitivity: { + focus: 'sensation', + adjustments: { + minimalTouch: true, + edgeControl: 'precise', + slowEdging: true + } + }, + MultiSensory: { + focus: 'overload', + adjustments: { + allFeatures: true, + simultaneousFeatures: 7, + complexityMax: true + } + } +}; +``` + +**Methods**: +```javascript +class IntensityManager { + // ... existing methods ... + + applyPathAdjustments(baseTasks, path) { + // Modify tasks based on path focus + } + + generatePathSpecificChallenge(level, path) { + // Create unique challenge for path at this level + } +} +``` + +**Testing Checklist**: +- [ ] Path adjustments apply +- [ ] Each path has unique L26-30 experience +- [ ] Adjustments respect preferences + +--- + +### Task 3: Graduation System (5-7 hours) + +**File to Create**: `src/features/academy/graduationManager.js` + +**Responsibilities**: +- Execute Level 30 (5-hour final exam) +- Generate graduation ceremony +- Create certificate +- Compile stats report +- Curate photo gallery +- Compile library report +- Unlock freeplay and Ascended mode +- Display graduation modal + +**Graduation Ceremony Components**: + +**1. Final Oath**: +```javascript +const graduationOath = { + base: "I am a graduate of The Academy.", + custom: (stats) => ` + I have completed ${stats.totalLevels} levels. + I have edged ${stats.totalEdges} times. + I have gooned for ${stats.totalHours} hours. + I have mastered ${stats.selectedPath}. + I am a dedicated gooner. + I will continue to goon. + I embrace my addiction. + ` +}; +``` + +**2. Certificate**: +```javascript +const certificate = { + title: "Certificate of Completion", + subtitle: "The Academy", + body: ` + This certifies that [USERNAME] has successfully completed + The Academy's comprehensive gooner training program. + + Path: [PATH] + Total Time: [HOURS] hours + Total Edges: [EDGES] + Library Size: [VIDEOS] videos, [IMAGES] images + Curator Rank: [RANK] + + Graduated: [DATE] + ` +}; +``` + +**3. Stats Report**: +```javascript +const statsReport = { + general: { + totalLevels: 30, + totalSessionTime: 0, // seconds + totalEdges: 0, + averageSessionLength: 0, + longestSession: 0, + failedAttempts: 0 + }, + features: { + webcamTimeUsed: 0, + ttsCommandsHeard: 0, + hypnoTimeWatched: 0, + captionsDisplayed: 0, + interruptionsCompleted: 0, + popupsViewed: 0 + }, + library: { + totalVideos: 0, + totalImages: 0, + taggedFiles: 0, + tagCoverage: 0, // % + curatorRank: 'Master', + topTags: [] + }, + path: { + selectedPath: '', + pathLevelsCompleted: 4, // L22-25 + pathSpecificStats: {} // depends on path + } +}; +``` + +**4. Photo Gallery**: +```javascript +// Collect photos from: +// - Dress-up game completions +// - Webcam snapshots (if enabled) +// - Achievement unlocks +// Display as gallery during ceremony +``` + +**5. Library Report**: +```javascript +const libraryReport = { + summary: "Your curated library contains X videos and Y images.", + coverage: "Z% of your library is tagged.", + curatorRank: "You achieved Master rank as a curator.", + topCategories: ["amateur", "POV", "edging"], + recommendations: "Continue curating to reach 100% coverage." +}; +``` + +**Methods**: +```javascript +class GraduationManager { + async executeGraduationLevel() { + // Run 5-hour Level 30 session + // Track all stats during session + } + + async startCeremony() { + // Show graduation modal + // Display oath → certificate → stats → photos → library + } + + generateCertificate(stats) { + // Fill template with user stats + // Return HTML certificate + } + + compileStatsReport() { + // Aggregate all stats from academyProgress + } + + compilePhotoGallery() { + // Collect photos from dress-up, webcam, achievements + } + + compileLibraryReport() { + // Generate summary from libraryData + } + + unlockPostGraduationContent() { + // Unlock freeplay mode + // Unlock Ascended mode + // Save to gameData + } + + saveCertificate() { + // Optionally save certificate as image/PDF + } +} +``` + +**Graduation Modal UI**: +```html + +``` + +**Testing Checklist**: +- [ ] Level 30 runs full 5-hour session +- [ ] Graduation ceremony triggers +- [ ] Oath displays and is recitable +- [ ] Certificate generates with correct stats +- [ ] Stats report compiles accurately +- [ ] Photo gallery displays +- [ ] Library report displays +- [ ] Freeplay unlocks +- [ ] Ascended mode unlocks + +--- + +### Task 4: Level Data for L26-30 (2-3 hours) + +**File to Update**: `src/data/modes/academyLevelData.js` + +Add levels 26-30: + +```javascript +const academyLevels = { + // ... L1-25 ... + + 26: { + name: "Ultimate Test I", + arc: "Ultimate Mastery", + duration: 14400, // 240 minutes (4 hours) + intensityStage: 1, + requirements: { + minLevel: 26, + completedLevels: [25] + }, + unlocks: { + level: 27 + }, + sessionStructure: { + main: [ + { type: 'apply-intensity', stage: 1 }, + { type: 'path-specific-challenge', level: 26 }, + { type: 'sensory-overload', duration: 14400 }, + { type: 'edge', params: { count: 200 } } + ] + } + }, + + 27: { + name: "Ultimate Test II", + arc: "Ultimate Mastery", + duration: 15300, // 255 minutes + intensityStage: 2, + requirements: { + minLevel: 27, + completedLevels: [26] + }, + unlocks: { + level: 28 + }, + sessionStructure: { + main: [ + { type: 'apply-intensity', stage: 2 }, + { type: 'path-specific-challenge', level: 27 }, + { type: 'sensory-overload', duration: 15300 }, + { type: 'edge', params: { count: 240 } } + ] + } + }, + + 28: { + name: "Ultimate Test III", + arc: "Ultimate Mastery", + duration: 16200, // 270 minutes + intensityStage: 3, + requirements: { + minLevel: 28, + completedLevels: [27] + }, + unlocks: { + level: 29 + }, + sessionStructure: { + main: [ + { type: 'apply-intensity', stage: 3 }, + { type: 'path-specific-challenge', level: 28 }, + { type: 'sensory-overload', duration: 16200 }, + { type: 'edge', params: { count: 280 } } + ] + } + }, + + 29: { + name: "Ultimate Test IV", + arc: "Ultimate Mastery", + duration: 17100, // 285 minutes + intensityStage: 4, + requirements: { + minLevel: 29, + completedLevels: [28] + }, + unlocks: { + level: 30 + }, + sessionStructure: { + main: [ + { type: 'apply-intensity', stage: 4 }, + { type: 'path-specific-challenge', level: 29 }, + { type: 'sensory-overload', duration: 17100 }, + { type: 'edge', params: { count: 320 } } + ] + } + }, + + 30: { + name: "Graduation", + arc: "Ultimate Mastery", + duration: 18000, // 300 minutes (5 hours) + intensityStage: 4, + isGraduation: true, + requirements: { + minLevel: 30, + completedLevels: [29] + }, + unlocks: { + graduation: true, + freeplay: true, + ascendedMode: true, + arcsCompleted: ['Ultimate Mastery'] + }, + sessionStructure: { + warmup: [ + { type: 'caption', text: 'This is it. Your final test.' } + ], + main: [ + { type: 'apply-intensity', stage: 4 }, + { type: 'path-specific-challenge', level: 30 }, + { type: 'sensory-overload', duration: 18000 }, + { type: 'edge', params: { count: 300 } } + ], + cooldown: [ + { type: 'start-graduation-ceremony' } + ] + } + } +}; +``` + +**Testing Checklist**: +- [ ] L26-30 defined +- [ ] Intensity stages apply +- [ ] L30 triggers graduation +- [ ] Graduation unlocks saved + +--- + +### Task 5: Freeplay & Ascended Mode Foundations (1-2 hours) + +**Basic Implementation** (full features in Phase 6/7): + +**Freeplay Mode**: +- Allow users to create custom sessions +- Select any features, any duration +- No progression requirements + +**Ascended Mode**: +- Ultra-hard version of any level +- 2x intensity multipliers +- Additional challenges +- For post-graduation mastery + +**Data Structure**: +```javascript +academyProgress: { + // ... existing ... + freeplayUnlocked: false, + ascendedModeUnlocked: false, + ascendedLevelsCompleted: [] +} +``` + +**Testing Checklist**: +- [ ] Freeplay mode accessible after graduation +- [ ] Ascended mode accessible after graduation +- [ ] Basic functionality works + +--- + +## 📏 Measurable Test Criteria + +After Phase 5, ALL of these must pass: + +### Level 26 (Ultimate Test I): +- [ ] 4-hour session runs +- [ ] Intensity Stage 1 applies (1.0x multipliers) +- [ ] Path-specific challenge loads +- [ ] Sensory overload coordinated +- [ ] Completing L26 unlocks L27 + +### Level 27 (Ultimate Test II): +- [ ] 4.25-hour session runs +- [ ] Intensity Stage 2 applies (1.2-1.3x multipliers) +- [ ] Difficulty increase noticeable +- [ ] Completing L27 unlocks L28 + +### Level 28 (Ultimate Test III): +- [ ] 4.5-hour session runs +- [ ] Intensity Stage 3 applies (1.4-1.6x multipliers) +- [ ] Difficulty significantly harder +- [ ] Completing L28 unlocks L29 + +### Level 29 (Ultimate Test IV): +- [ ] 4.75-hour session runs +- [ ] Intensity Stage 4 applies (1.6-2.0x multipliers) +- [ ] Maximum difficulty before graduation +- [ ] Completing L29 unlocks L30 + +### Level 30 (Graduation): +- [ ] 5-hour final session runs +- [ ] Path-specific final challenge loads +- [ ] All features coordinate perfectly +- [ ] Session completes successfully +- [ ] Graduation ceremony triggers + +### Graduation Ceremony: +- [ ] Oath displays correctly +- [ ] Certificate generates with accurate stats +- [ ] Stats report compiles (30 levels, total time, edges, path) +- [ ] Photo gallery displays (if photos exist) +- [ ] Library report displays (tag coverage, curator rank) +- [ ] Certificate downloadable +- [ ] Freeplay unlocks +- [ ] Ascended mode unlocks +- [ ] Ultimate Mastery arc completes +- [ ] `graduationCompleted` flag set to true + +### Overall: +- [ ] All levels L26-30 playable +- [ ] Intensity progression works +- [ ] Path adjustments apply +- [ ] No console errors +- [ ] Progress saves after each level +- [ ] Can complete L26 → L30 sequentially +- [ ] Graduation persistent after refresh + +--- + +## 🎯 Success Criteria + +**Phase 5 Complete When:** +1. Levels 26-30 fully functional +2. Ultimate Mastery arc complete +3. Progressive intensity system works +4. Graduation ceremony executes perfectly +5. Certificate, stats, photos, library all display +6. Freeplay and Ascended mode unlock +7. All measurable tests pass +8. Campaign finale satisfying and complete + +--- + +## 📂 Files Created/Modified + +### New Files: +- `src/features/academy/intensityManager.js` +- `src/features/academy/graduationManager.js` + +### Modified Files: +- `src/data/modes/academyLevelData.js` +- `src/core/gameDataManager.js` +- `training-academy.html` + +--- + +## 🚀 Next Phase + +After Phase 5: **Phase 6: Stats/Achievements/Library Systems** (Cross-cutting systems) diff --git a/docs/training-game-redesign/PHASE-6.md b/docs/training-game-redesign/PHASE-6.md new file mode 100644 index 0000000..3798056 --- /dev/null +++ b/docs/training-game-redesign/PHASE-6.md @@ -0,0 +1,755 @@ +# Phase 6: Stats/Achievements/Library Systems + +**Priority**: MEDIUM - Cross-cutting systems for engagement +**Estimated Effort**: 14-18 hours +**Status**: Not Started +**Dependencies**: Phase 1 (for library foundation), can run parallel with Phase 2-5 + +--- + +## 🎯 Phase Goals + +Implement comprehensive statistics tracking, achievement system, and advanced library management. These cross-cutting systems enhance engagement throughout the entire campaign and provide depth for post-graduation content. + +--- + +## 📋 What This Phase Delivers + +### Core Systems: +1. **Statistics Dashboard** - Track all Academy metrics +2. **Achievement System** - 25+ achievements with unlock notifications +3. **Advanced Library Management** - Quality scoring, diversity scoring, smart playlists +4. **Curator Rank Progression** - Novice → Master with benefits +5. **Stats Visualization** - Charts, graphs, progress bars +6. **Export/Import** - Save/load library data, share achievements + +**End Result**: Rich meta-game layer that rewards progress and curation. + +--- + +## 🏗️ Implementation Tasks + +### Task 1: Achievement System (5-6 hours) + +**File to Create**: `src/features/academy/progressionManager.js` + +**Responsibilities**: +- Define all achievements +- Track achievement progress +- Unlock achievements +- Display achievement notifications +- Achievement showcase + +**Achievement Definitions**: +```javascript +const achievements = [ + // Progression Achievements + { + id: 'first_level', + name: 'First Steps', + description: 'Complete Level 1', + icon: '🎓', + category: 'progression', + condition: (stats) => stats.completedLevels.includes(1), + reward: null + }, + { + id: 'foundation_complete', + name: 'Foundation Graduate', + description: 'Complete the Foundation Arc (L1-5)', + icon: '🏛️', + category: 'progression', + condition: (stats) => stats.completedLevels.length >= 5, + reward: null + }, + { + id: 'halfway', + name: 'Halfway There', + description: 'Complete 15 levels', + icon: '🔥', + category: 'progression', + condition: (stats) => stats.completedLevels.length >= 15, + reward: null + }, + { + id: 'all_30', + name: 'Academy Graduate', + description: 'Complete all 30 levels', + icon: '🎓', + category: 'progression', + condition: (stats) => stats.graduationCompleted, + reward: 'Certificate of Completion' + }, + + // Edging Achievements + { + id: 'edge_100', + name: 'Century Club', + description: 'Edge 100 times total', + icon: '💯', + category: 'edging', + condition: (stats) => stats.totalEdges >= 100, + reward: null + }, + { + id: 'edge_500', + name: 'Edge Master', + description: 'Edge 500 times total', + icon: '🔥', + category: 'edging', + condition: (stats) => stats.totalEdges >= 500, + reward: null + }, + { + id: 'edge_1000', + name: 'Edge Legend', + description: 'Edge 1000 times total', + icon: '⭐', + category: 'edging', + condition: (stats) => stats.totalEdges >= 1000, + reward: null + }, + + // Time Achievements + { + id: 'time_10h', + name: '10 Hours Strong', + description: 'Goon for 10 hours total', + icon: '⏰', + category: 'time', + condition: (stats) => stats.totalSessionTime >= 36000, // 10 hours in seconds + reward: null + }, + { + id: 'time_50h', + name: 'Dedicated Gooner', + description: 'Goon for 50 hours total', + icon: '⏱️', + category: 'time', + condition: (stats) => stats.totalSessionTime >= 180000, // 50 hours + reward: null + }, + { + id: 'time_100h', + name: 'Gooner for Life', + description: 'Goon for 100 hours total', + icon: '🏆', + category: 'time', + condition: (stats) => stats.totalSessionTime >= 360000, // 100 hours + reward: 'Honorary Title: Eternal Gooner' + }, + + // Feature Achievements + { + id: 'webcam_unlock', + name: 'The Observer', + description: 'Unlock webcam feature', + icon: '📹', + category: 'features', + condition: (stats) => stats.featuresUnlocked.includes('webcam'), + reward: null + }, + { + id: 'all_features', + name: 'Feature Complete', + description: 'Unlock all features', + icon: '🎯', + category: 'features', + condition: (stats) => stats.featuresUnlocked.length >= 10, + reward: null + }, + + // Library Achievements + { + id: 'first_directory', + name: 'Curator Initiate', + description: 'Add your first directory to the library', + icon: '📁', + category: 'library', + condition: (stats) => stats.library.directories.length >= 1, + reward: null + }, + { + id: 'tag_100', + name: 'Tagger', + description: 'Tag 100 files', + icon: '🏷️', + category: 'library', + condition: (stats) => stats.library.taggedFiles >= 100, + reward: null + }, + { + id: 'tag_500', + name: 'Master Tagger', + description: 'Tag 500 files', + icon: '🏷️', + category: 'library', + condition: (stats) => stats.library.taggedFiles >= 500, + reward: null + }, + { + id: 'coverage_90', + name: 'Meticulous Curator', + description: 'Reach 90% tag coverage', + icon: '✨', + category: 'library', + condition: (stats) => stats.library.tagCoverage >= 90, + reward: null + }, + { + id: 'curator_master', + name: 'Master Curator', + description: 'Achieve Master curator rank', + icon: '👑', + category: 'library', + condition: (stats) => stats.library.curatorRank === 'Master', + reward: 'Access to advanced library features' + }, + + // Challenge Achievements + { + id: 'marathon_first', + name: 'Marathon Runner', + description: 'Complete your first marathon session (15x)', + icon: '🏃', + category: 'challenge', + condition: (stats) => stats.marathonSessionsCompleted >= 1, + reward: null + }, + { + id: 'no_failures', + name: 'Flawless', + description: 'Complete 10 levels without any failures', + icon: '💎', + category: 'challenge', + condition: (stats) => stats.consecutiveLevelsWithoutFailure >= 10, + reward: null + }, + { + id: 'path_master', + name: 'Path Master', + description: 'Complete your chosen path (L22-25)', + icon: '🛤️', + category: 'challenge', + condition: (stats) => stats.pathLevelsCompleted >= 4, + reward: null + }, + + // Hidden Achievements + { + id: 'secret_ascended', + name: 'Ascended', + description: 'Complete 5 Ascended Mode levels', + icon: '🌟', + category: 'hidden', + hidden: true, + condition: (stats) => stats.ascendedLevelsCompleted >= 5, + reward: 'Secret reward' + }, + { + id: 'secret_perfectionist', + name: 'Perfectionist', + description: 'Complete all 30 levels without any failures', + icon: '🏆', + category: 'hidden', + hidden: true, + condition: (stats) => stats.completedLevels.length === 30 && stats.totalFailedAttempts === 0, + reward: 'Ultimate gooner title' + } + + // Total: 25+ achievements +]; +``` + +**Methods**: +```javascript +class ProgressionManager { + checkAchievements(stats) { + // Loop through all achievements + // Check conditions + // Unlock new achievements + // Return newly unlocked achievements + } + + unlockAchievement(achievementId) { + // Set achievement as unlocked + // Show notification + // Save to gameData + } + + getUnlockedAchievements() { + // Return list of unlocked achievements + } + + getAchievementProgress(achievementId) { + // For progressive achievements, return % progress + } + + displayAchievementNotification(achievement) { + // Show toast notification + // "Achievement Unlocked: [NAME]" + } +} +``` + +**Achievement Notification UI**: +```html + +``` + +**Testing Checklist**: +- [ ] All 25+ achievements defined +- [ ] Achievement conditions check correctly +- [ ] Achievements unlock at right moments +- [ ] Notifications display +- [ ] Achievements persist +- [ ] Hidden achievements stay hidden until unlocked + +--- + +### Task 2: Statistics Dashboard (4-5 hours) + +**File to Update**: `src/features/academy/progressionManager.js` +**File to Create**: `src/features/academy/statsVisualizer.js` + +**Stats to Track**: +```javascript +const academyStats = { + // Progression + currentLevel: 1, + highestUnlockedLevel: 1, + completedLevels: [], + arcsCompleted: [], + + // Time + totalSessionTime: 0, // seconds + longestSession: 0, // seconds + averageSessionLength: 0, // seconds + lastPlayedDate: null, + + // Edging + totalEdges: 0, + edgesPerLevel: {}, // { level: count } + averageEdgesPerSession: 0, + + // Features + featuresUnlocked: [], + webcamTimeUsed: 0, + ttsCommandsHeard: 0, + hypnoTimeWatched: 0, + captionsDisplayed: 0, + interruptionsCompleted: 0, + popupsViewed: 0, + + // Library + library: { + totalFiles: 0, + taggedFiles: 0, + tagCoverage: 0, + curatorRank: 'Novice', + directoriesAdded: 0 + }, + + // Path + selectedPath: null, + pathLevelsCompleted: 0, + + // Failures + totalFailedAttempts: 0, + failuresByReason: { + cumming: 0, + abandoned: 0, + featureClosed: 0 + }, + consecutiveLevelsWithoutFailure: 0, + + // Achievements + achievementsUnlocked: [], + achievementProgress: {} +}; +``` + +**Stats Dashboard UI**: +```html +
+

Academy Statistics

+ +
+

Progression

+

Current Level:

+

Completed Levels: / 30

+
+
+
+

Arcs Completed:

+
+ +
+

Time Investment

+

Total Time:

+

Longest Session:

+

Average Session:

+
+ +
+

Edging Statistics

+

Total Edges:

+

Average per Session:

+ +
+ +
+

Feature Usage

+
    +
  • Webcam Time:
  • +
  • TTS Commands:
  • +
  • Hypno Time:
  • +
  • Captions Shown:
  • +
  • Interruptions:
  • +
  • Popups Viewed:
  • +
+
+ +
+

Library Curation

+

Total Files:

+

Tagged Files:

+

Tag Coverage: %

+
+
+
+

Curator Rank:

+
+ +
+

Achievements

+
+ +
+
+
+``` + +**Visualization Methods**: +```javascript +class StatsVisualizer { + renderProgressBar(percent, elementId) { + // Update progress bar width + } + + renderEdgeChart(edgesPerLevel) { + // Use Chart.js or similar to render edge graph + } + + formatTime(seconds) { + // Convert seconds to "Xh Ym" format + } + + renderAchievementGrid(achievements) { + // Display unlocked + locked achievements + } +} +``` + +**Testing Checklist**: +- [ ] All stats track correctly +- [ ] Dashboard displays all sections +- [ ] Progress bars update +- [ ] Charts render correctly +- [ ] Time formats correctly +- [ ] Achievement grid displays + +--- + +### Task 3: Advanced Library Management (3-4 hours) + +**File to Update**: `src/features/academy/libraryManager.js` + +**New Features**: +1. **Quality Scoring** - Rate files 1-5 stars +2. **Diversity Scoring** - Measure tag variety +3. **Smart Playlists** - Auto-generate playlists from tags + +**Quality Scoring**: +```javascript +class LibraryManager { + // ... existing methods ... + + rateFile(filePath, rating) { + // rating: 1-5 stars + // Save to individualFiles + } + + getHighestRatedFiles(count = 10) { + // Return top-rated files + } + + calculateAverageQuality() { + // Average rating across all rated files + } +} +``` + +**Diversity Scoring**: +```javascript +class LibraryManager { + // ... existing ... + + calculateDiversityScore() { + // Count unique tags + // Compare to total tags in catalog + // Return % (0-100) + } + + getUnderrepresentedTags() { + // Return tags with < 10 files + // Suggest adding content with these tags + } +} +``` + +**Smart Playlists**: +```javascript +class LibraryManager { + // ... existing ... + + createSmartPlaylist(name, tagCombination, matchMode = 'AND') { + // tagCombination: ['amateur', 'pov'] + // matchMode: 'AND' or 'OR' + // Return playlist of matching files + } + + getSuggestedPlaylists(preferences) { + // Based on user preferences, suggest playlists + // e.g., "Sissy + Humiliation", "Denial + Edging" + } + + savePlaylist(playlist) { + // Save to gameData + } + + loadPlaylists() { + // Return all saved playlists + } +} +``` + +**Smart Playlist UI**: +```html +
+

Smart Playlists

+ + + + +
+ +
+
+``` + +**Testing Checklist**: +- [ ] Can rate files 1-5 stars +- [ ] Quality score calculates +- [ ] Diversity score calculates +- [ ] Smart playlists create correctly +- [ ] Playlists save and load +- [ ] Suggested playlists generate + +--- + +### Task 4: Curator Rank Benefits (2-3 hours) + +**Curator Rank System**: +```javascript +const curatorRanks = { + Novice: { + minCoverage: 0, + benefits: ['Basic tagging'] + }, + Apprentice: { + minCoverage: 50, + benefits: ['Bulk tagging', 'Tag suggestions'] + }, + Journeyman: { + minCoverage: 75, + benefits: ['Smart playlists', 'Quality rating'] + }, + Expert: { + minCoverage: 90, + benefits: ['Advanced filters', 'Diversity insights'] + }, + Master: { + minCoverage: 98, + benefits: ['Full library analytics', 'Export/import', 'Custom tags'] + } +}; +``` + +**Rank-Gated Features**: +- **Bulk Tagging**: Apprentice+ can tag multiple files at once +- **Smart Playlists**: Journeyman+ can create smart playlists +- **Advanced Filters**: Expert+ can filter by multiple criteria +- **Export/Import**: Master can export library data + +**Testing Checklist**: +- [ ] Rank calculates based on coverage +- [ ] Benefits unlock at correct ranks +- [ ] Features gate correctly + +--- + +### Task 5: Export/Import System (2-3 hours) + +**File to Create**: `src/features/academy/dataExporter.js` + +**Responsibilities**: +- Export library data as JSON +- Export achievements as JSON +- Import library data +- Share library configurations + +**Methods**: +```javascript +class DataExporter { + exportLibrary() { + // Return JSON of libraryData + } + + exportAchievements() { + // Return JSON of unlocked achievements + } + + importLibrary(jsonData) { + // Merge imported data with existing library + // Avoid duplicates + } + + downloadAsFile(data, filename) { + // Trigger browser download + } +} +``` + +**UI**: +```html +
+

Data Management

+ + + + +
+``` + +**Testing Checklist**: +- [ ] Library exports as JSON +- [ ] Achievements export as JSON +- [ ] Import merges correctly +- [ ] No duplicate entries after import + +--- + +## 📏 Measurable Test Criteria + +After Phase 6, ALL of these must pass: + +### Achievement System: +- [ ] All 25+ achievements defined +- [ ] "First Steps" unlocks after L1 +- [ ] "Foundation Graduate" unlocks after L5 +- [ ] "Century Club" unlocks at 100 edges +- [ ] "10 Hours Strong" unlocks at 10 hours +- [ ] "Curator Initiate" unlocks after adding first directory +- [ ] Achievement notifications display +- [ ] Achievements persist across refresh +- [ ] Hidden achievements stay hidden + +### Statistics Dashboard: +- [ ] Dashboard displays all sections +- [ ] Current level displays correctly +- [ ] Completed levels count correct +- [ ] Progress bar updates +- [ ] Total time calculates correctly +- [ ] Total edges track correctly +- [ ] Feature usage stats accurate +- [ ] Library stats display +- [ ] Achievement grid shows unlocked + locked + +### Library Management: +- [ ] Can rate files 1-5 stars +- [ ] Average quality calculates +- [ ] Diversity score calculates +- [ ] Smart playlists create +- [ ] Playlists save and load +- [ ] Tag suggestions work + +### Curator Ranks: +- [ ] Novice at 0% coverage +- [ ] Apprentice at 50% coverage +- [ ] Journeyman at 75% coverage +- [ ] Expert at 90% coverage +- [ ] Master at 98% coverage +- [ ] Benefits unlock correctly + +### Export/Import: +- [ ] Library exports as valid JSON +- [ ] Achievements export as valid JSON +- [ ] Import merges without duplicates +- [ ] Download triggers correctly + +### Overall: +- [ ] No console errors +- [ ] All systems persist data +- [ ] Performance acceptable with large library + +--- + +## 🎯 Success Criteria + +**Phase 6 Complete When:** +1. Achievement system fully functional (25+ achievements) +2. Stats dashboard displays all metrics +3. Advanced library features work (quality, diversity, playlists) +4. Curator rank progression works +5. Export/import functional +6. All measurable tests pass +7. Meta-game layer enhances engagement + +--- + +## 📂 Files Created/Modified + +### New Files: +- `src/features/academy/progressionManager.js` +- `src/features/academy/statsVisualizer.js` +- `src/features/academy/dataExporter.js` +- `src/data/academy/achievements.js` + +### Modified Files: +- `src/features/academy/libraryManager.js` +- `src/core/gameDataManager.js` +- `training-academy.html` + +--- + +## 🚀 Next Phase + +After Phase 6: **Phase 7: Polish/UI/UX/Testing** (Final refinements and QA) diff --git a/docs/training-game-redesign/PHASE-7.md b/docs/training-game-redesign/PHASE-7.md new file mode 100644 index 0000000..aee5f58 --- /dev/null +++ b/docs/training-game-redesign/PHASE-7.md @@ -0,0 +1,752 @@ +# Phase 7: Polish, UI/UX & Testing + +**Priority**: HIGH - Final quality assurance +**Estimated Effort**: 12-16 hours +**Status**: Not Started +**Dependencies**: Phases 1-6 complete + +--- + +## 🎯 Phase Goals + +Final polish, UI/UX improvements, comprehensive testing, and quality assurance. Ensure The Academy is polished, accessible, performant, and bug-free before launch. + +--- + +## 📋 What This Phase Delivers + +### Polish Areas: +1. **UI/UX Refinements** - Dark mode, animations, responsive design +2. **Accessibility Features** - Safe word, keyboard navigation, pause functionality +3. **Performance Optimization** - Loading times, video buffering, memory management +4. **Error Handling** - Graceful failures, user-friendly error messages +5. **Comprehensive Testing** - L1→L30 playthrough, all features, all paths +6. **Documentation** - User guide, tooltips, onboarding + +**End Result**: Production-ready Academy with excellent user experience. + +--- + +## 🏗️ Implementation Tasks + +### Task 1: UI/UX Refinements (4-5 hours) + +#### 1.1 Dark Mode Enhancement +**Current**: Basic dark styling +**Goal**: Polished dark theme with proper contrast + +**Updates Needed**: +```css +/* src/styles/styles-dark-edgy.css */ + +:root { + --bg-primary: #0a0a0a; + --bg-secondary: #1a1a1a; + --bg-tertiary: #2a2a2a; + --text-primary: #e0e0e0; + --text-secondary: #a0a0a0; + --accent-primary: #ff006e; + --accent-secondary: #8338ec; + --border-color: #333; + --success-color: #06ffa5; + --warning-color: #ffbe0b; + --error-color: #ff006e; +} + +/* Smooth transitions */ +* { + transition: background-color 0.2s ease, color 0.2s ease; +} + +/* Card styling */ +.level-card { + background: var(--bg-secondary); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 16px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); +} + +.level-card:hover { + background: var(--bg-tertiary); + border-color: var(--accent-primary); + box-shadow: 0 6px 12px rgba(255, 0, 110, 0.2); +} + +/* Button styling */ +button { + background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)); + color: white; + border: none; + border-radius: 4px; + padding: 12px 24px; + cursor: pointer; + font-weight: 600; +} + +button:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(255, 0, 110, 0.4); +} + +button:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; +} +``` + +#### 1.2 Animations +Add smooth transitions for modals, level unlocks, achievements: + +```css +/* Modal animations */ +.modal { + animation: fadeIn 0.3s ease; +} + +@keyframes fadeIn { + from { opacity: 0; transform: scale(0.9); } + to { opacity: 1; transform: scale(1); } +} + +/* Level unlock animation */ +.level-card.unlocked { + animation: unlock 0.5s ease; +} + +@keyframes unlock { + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } + 100% { transform: scale(1); } +} + +/* Achievement toast */ +.achievement-toast { + animation: slideInRight 0.5s ease; +} + +@keyframes slideInRight { + from { transform: translateX(400px); opacity: 0; } + to { transform: translateX(0); opacity: 1; } +} +``` + +#### 1.3 Responsive Design +Ensure mobile/tablet compatibility: + +```css +/* Mobile adjustments */ +@media (max-width: 768px) { + .level-grid { + grid-template-columns: repeat(2, 1fr); + } + + .quad-video { + grid-template-columns: 1fr; + } + + .stats-dashboard { + flex-direction: column; + } +} + +/* Tablet adjustments */ +@media (min-width: 769px) and (max-width: 1024px) { + .level-grid { + grid-template-columns: repeat(3, 1fr); + } +} +``` + +**Testing Checklist**: +- [ ] Dark mode looks polished +- [ ] All buttons have hover states +- [ ] Modals animate smoothly +- [ ] Level unlocks animate +- [ ] Achievement toasts slide in +- [ ] Responsive on mobile (320px+) +- [ ] Responsive on tablet (768px+) + +--- + +### Task 2: Accessibility Features (3-4 hours) + +#### 2.1 Safe Word System +**Critical safety feature** for immediate session stop: + +```javascript +// src/features/academy/safeWordManager.js +class SafeWordManager { + constructor() { + this.safeWord = localStorage.getItem('safeWord') || 'STOP'; + this.listening = false; + } + + setSafeWord(word) { + this.safeWord = word.toUpperCase(); + localStorage.setItem('safeWord', this.safeWord); + } + + startListening() { + this.listening = true; + document.addEventListener('keydown', this.handleKeypress.bind(this)); + } + + stopListening() { + this.listening = false; + document.removeEventListener('keydown', this.handleKeypress.bind(this)); + } + + handleKeypress(event) { + // Listen for safe word typed + // If detected, immediately stop session + if (this.detectSafeWord(event.key)) { + this.triggerEmergencyStop(); + } + } + + triggerEmergencyStop() { + // Stop all media + // Close all overlays + // Return to level select + // Show "Session stopped safely" message + } +} +``` + +**UI**: +```html +
+

Safe Word

+

Set a safe word to immediately stop any session.

+ + +

Current: STOP

+
+ + +``` + +#### 2.2 Keyboard Navigation +Full keyboard accessibility: + +```javascript +// Add keyboard shortcuts +const keyboardShortcuts = { + 'Escape': () => pauseSession(), + 'Space': () => togglePlayPause(), + 'p': () => openPreferences(), + 's': () => openStats(), + 'l': () => openLibrary(), + '1-9': (num) => quickSelectLevel(num) +}; + +// Focus management +function manageFocus() { + // Ensure modals trap focus + // Tab through interactive elements + // Return focus on modal close +} +``` + +#### 2.3 Pause Functionality +Allow pausing any session: + +```javascript +class SessionManager { + pause() { + // Pause all videos + // Stop TTS + // Pause timers + // Show pause overlay + } + + resume() { + // Resume all activities + // Continue timers from pause point + } +} +``` + +**UI**: +```html + + + +``` + +**Testing Checklist**: +- [ ] Safe word can be set +- [ ] Safe word triggers emergency stop +- [ ] All features stop immediately +- [ ] Keyboard shortcuts work +- [ ] Tab navigation works in modals +- [ ] Pause button accessible +- [ ] Pause/resume works correctly +- [ ] Timer resumes from pause point + +--- + +### Task 3: Performance Optimization (2-3 hours) + +#### 3.1 Video Buffering +Pre-load videos to prevent stuttering: + +```javascript +class VideoPreloader { + preloadVideo(videoPath) { + const video = document.createElement('video'); + video.src = videoPath; + video.preload = 'auto'; + video.load(); + return video; + } + + preloadNextLevelVideos(nextLevel) { + // Pre-load videos for next level + // Do this during current level + } +} +``` + +#### 3.2 Memory Management +Clean up resources: + +```javascript +class ResourceManager { + cleanup() { + // Stop all videos + // Clear intervals/timeouts + // Remove event listeners + // Garbage collect large objects + } + + cleanupAfterLevel() { + // Remove unused videos from DOM + // Clear temporary data + } +} +``` + +#### 3.3 Loading States +Show loading indicators: + +```html + +``` + +**Testing Checklist**: +- [ ] Videos buffer before playback +- [ ] No stuttering during playback +- [ ] Memory usage stays stable +- [ ] No memory leaks over long sessions +- [ ] Loading indicators show during waits +- [ ] Resource cleanup works + +--- + +### Task 4: Error Handling (2-3 hours) + +#### 4.1 Graceful Failures +Handle errors without crashing: + +```javascript +class ErrorHandler { + handleVideoLoadError(videoPath) { + console.error(`Video failed to load: ${videoPath}`); + // Try alternate video + // Or skip video action + // Show user-friendly message + showMessage('Video unavailable. Using alternative...'); + } + + handleFeatureError(feature) { + console.error(`Feature failed: ${feature}`); + // Disable feature gracefully + // Continue session without it + showMessage(`${feature} unavailable. Continuing...`); + } + + handleDataSaveError() { + console.error('Failed to save progress'); + // Retry save + // Offer manual export + showMessage('Warning: Progress may not be saved. Export data manually.'); + } +} +``` + +#### 4.2 User-Friendly Error Messages +Replace technical errors: + +```javascript +const errorMessages = { + 'VIDEO_NOT_FOUND': 'The video file could not be found. Check your media library.', + 'SAVE_FAILED': 'Could not save your progress. Try exporting your data.', + 'WEBCAM_DENIED': 'Webcam access denied. Enable in browser settings.', + 'FEATURE_UNAVAILABLE': 'This feature is currently unavailable.', + 'NETWORK_ERROR': 'Network error. Some features may not work.' +}; + +function showError(errorCode) { + const message = errorMessages[errorCode] || 'An error occurred.'; + showModal('Error', message); +} +``` + +**Testing Checklist**: +- [ ] Missing video handled gracefully +- [ ] Feature failures don't crash app +- [ ] Data save errors handled +- [ ] User-friendly error messages shown +- [ ] Errors logged to console for debugging +- [ ] Can recover from errors without refresh + +--- + +### Task 5: Comprehensive Testing (4-6 hours) + +#### 5.1 Full Campaign Playthrough +Test every level sequentially: + +**Test Plan**: +``` +✅ Level 1-5 (Foundation Arc) + - [ ] L1: Edge training works + - [ ] L2: Rhythm + library addition works + - [ ] L3: Video + file tagging works + - [ ] L4: Multi-tasking works + - [ ] L5: Checkpoint + preferences work + +✅ Level 6-10 (Feature Discovery Arc) + - [ ] L6: Webcam enables + - [ ] L7: Dual video works + - [ ] L8: TTS works + - [ ] L9: Quad video works + - [ ] L10: Hypno + checkpoint work + +✅ Level 11-15 (Mind & Body Arc) + - [ ] L11: Hypno + captions work + - [ ] L12: Dynamic captions work + - [ ] L13: TTS + hypno sync works + - [ ] L14: Sensory overload works + - [ ] L15: Checkpoint works + +✅ Level 16-20 (Advanced Training Arc) + - [ ] L16: Interruptions work + - [ ] L17: Denial training works + - [ ] L18: Popups work + - [ ] L19: Total immersion works + - [ ] L20: Ultimate checkpoint works + +✅ Level 21-25 (Path Specialization Arc) + - [ ] L21: Path selection works + - [ ] L22-24: Path-specific content works for all 6 paths + - [ ] L25: Path graduation works + +✅ Level 26-30 (Ultimate Mastery Arc) + - [ ] L26-29: Intensity progression works + - [ ] L30: Graduation ceremony works + - [ ] Certificate generates + - [ ] Stats report accurate + - [ ] Freeplay unlocks + - [ ] Ascended mode unlocks +``` + +#### 5.2 Feature Testing +Test all features independently: + +``` +✅ Features + - [ ] Webcam: Starts, displays, stops + - [ ] Video players: Focus, overlay, quad all work + - [ ] TTS: Speaks commands correctly + - [ ] Hypno spiral: Animates smoothly + - [ ] Captions: Display, auto-generate, theme-based + - [ ] Interruptions: Random, pause/resume, all types + - [ ] Popups: Random, filtered, auto-hide + - [ ] Audio: Background music, metronome, hypno tracks +``` + +#### 5.3 Data Persistence Testing +Ensure all data saves/loads: + +``` +✅ Data Persistence + - [ ] Campaign progress saves + - [ ] Preferences save + - [ ] Library data saves + - [ ] Achievements save + - [ ] Stats save + - [ ] All data loads on refresh + - [ ] No data loss on browser close +``` + +#### 5.4 Edge Case Testing +Test unusual scenarios: + +``` +✅ Edge Cases + - [ ] Complete L1 → immediately refresh → L2 still unlocked + - [ ] Fail L5 → restart → preferences re-appear + - [ ] Close webcam mid-session → graceful failure + - [ ] Change preferences at all 6 checkpoints → preferences apply + - [ ] Tag 1000+ files → performance acceptable + - [ ] Complete all 30 levels → all features unlocked + - [ ] Try Ascended mode → ultra-hard works + - [ ] Export library → import on fresh profile → data intact +``` + +#### 5.5 Cross-Browser Testing +Test in multiple browsers: + +``` +✅ Browsers + - [ ] Chrome/Edge (Chromium) + - [ ] Firefox + - [ ] Safari (if applicable) + - [ ] Mobile browsers (Chrome, Safari) +``` + +#### 5.6 Accessibility Testing +Test with accessibility tools: + +``` +✅ Accessibility + - [ ] Screen reader compatibility (basic) + - [ ] Keyboard-only navigation works + - [ ] Color contrast sufficient (WCAG AA) + - [ ] Focus indicators visible + - [ ] Safe word accessible via keyboard +``` + +**Testing Checklist**: +- [ ] All 30 levels playable L1→L30 +- [ ] All features functional +- [ ] All data persists +- [ ] No console errors in normal flow +- [ ] Works in Chrome/Edge +- [ ] Works in Firefox +- [ ] Mobile-responsive +- [ ] Keyboard navigation works +- [ ] Safe word works +- [ ] No crashes or freezes + +--- + +### Task 6: Documentation & Onboarding (1-2 hours) + +#### 6.1 In-App Help +Add tooltips and help text: + +```html + +
+ Hover over ? icons for help +
+ + +
+

Level 1: Edge Training 101

+

Learn the basics of edging. Duration: 5 minutes.

+

Requirements: None

+

Unlocks: Level 2

+
+``` + +#### 6.2 First-Time User Onboarding +Guide new users: + +```html + +``` + +#### 6.3 User Guide (Markdown) +Create `docs/USER-GUIDE.md`: + +```markdown +# The Academy - User Guide + +## Overview +The Academy is a 30-level progressive gooner training program... + +## Getting Started +1. Start with Level 1 +2. Complete each level to unlock the next +3. Set preferences at checkpoints (L1, 5, 10, 15, 20, 25) + +## Features +- Webcam: Watch yourself (unlocks L6) +- TTS: Voice commands (unlocks L8) +... + +## Safety +- Set a safe word in settings +- Press Escape to pause any session +... + +## FAQ +Q: Can I skip levels? +A: No, levels must be completed in order. +... +``` + +**Testing Checklist**: +- [ ] Tooltips display +- [ ] Level info shows +- [ ] Welcome modal appears for new users +- [ ] User guide complete and accurate + +--- + +## 📏 Measurable Test Criteria + +After Phase 7, ALL of these must pass: + +### UI/UX: +- [ ] Dark mode polished +- [ ] All animations smooth +- [ ] Responsive on mobile (320px+) +- [ ] Responsive on tablet (768px+) +- [ ] All buttons have hover states +- [ ] Modals animate in/out +- [ ] Level unlocks animate + +### Accessibility: +- [ ] Safe word can be set +- [ ] Safe word stops session immediately +- [ ] Keyboard shortcuts work (Escape, Space, p, s, l) +- [ ] Tab navigation works +- [ ] Pause/resume functional +- [ ] Focus management correct in modals + +### Performance: +- [ ] Videos buffer before playback +- [ ] No stuttering during 5-hour session +- [ ] Memory stable over long sessions +- [ ] Loading indicators show +- [ ] Resource cleanup works + +### Error Handling: +- [ ] Missing videos handled gracefully +- [ ] Feature failures don't crash app +- [ ] User-friendly error messages +- [ ] Can recover from errors + +### Comprehensive Testing: +- [ ] All 30 levels playable sequentially +- [ ] All features work +- [ ] All data persists +- [ ] Works in Chrome/Edge +- [ ] Works in Firefox +- [ ] Mobile-responsive +- [ ] No critical bugs + +### Documentation: +- [ ] Tooltips helpful +- [ ] Welcome modal informative +- [ ] User guide complete + +--- + +## 🎯 Success Criteria + +**Phase 7 Complete When:** +1. UI/UX polished and responsive +2. Accessibility features functional (safe word, keyboard nav, pause) +3. Performance optimized (no stuttering, stable memory) +4. Error handling graceful +5. Full L1→L30 playthrough successful +6. All features tested and working +7. No critical bugs +8. Cross-browser compatible +9. Documentation complete +10. **Ready for launch** + +--- + +## 📂 Files Created/Modified + +### New Files: +- `src/features/academy/safeWordManager.js` +- `src/utils/errorHandler.js` +- `src/utils/performanceMonitor.js` +- `docs/USER-GUIDE.md` + +### Modified Files: +- `src/styles/styles-dark-edgy.css` (polish) +- `training-academy.html` (accessibility, onboarding) +- All manager files (error handling) + +--- + +## 🎉 Launch Readiness + +After Phase 7, The Academy is **production-ready**: + +✅ 30 levels fully functional +✅ 6 arcs complete +✅ All features unlocked progressively +✅ Preference system working +✅ Library tagging complete +✅ 25+ achievements +✅ Stats dashboard +✅ Graduation ceremony +✅ Freeplay & Ascended modes +✅ Polished UI/UX +✅ Accessible & safe +✅ Performant & stable +✅ Well-documented + +**Total Development Time**: 108-142 hours +**Total Levels**: 30 +**Total Features**: 10+ +**Total Achievements**: 25+ + +--- + +## 🚀 Post-Launch + +**Future Enhancements** (optional): +- Community features (share achievements, playlists) +- Additional paths +- Seasonal events +- Advanced analytics +- Mobile app version + +**Maintenance**: +- Monitor for bugs +- Update media library +- Add new achievements +- Respond to user feedback diff --git a/docs/training-game-redesign/PHASE-8-POLISH.md b/docs/training-game-redesign/PHASE-8-POLISH.md new file mode 100644 index 0000000..f899d04 --- /dev/null +++ b/docs/training-game-redesign/PHASE-8-POLISH.md @@ -0,0 +1,223 @@ +# Phase 8: Polish & Refinement + +**Priority**: MEDIUM - Quality of Life improvements +**Estimated Effort**: 8-12 hours +**Status**: Not Started +**Dependencies**: Phases 1-7 complete + +--- + +## 🎯 Phase Goals + +Polish and refine The Academy experience based on testing feedback. Focus on UI/UX improvements, feature enhancements, and quality of life updates that emerged during implementation and testing. + +--- + +## 📋 Action Items + +### UI/UX Improvements + +#### Scenario Display Enhancement +- [ ] **Improve typography and spacing** + - Better font hierarchy (titles, body, instructions) + - Consistent padding/margins throughout scenarios + - Improved line height and readability + +- [ ] **Visual design upgrades** + - More engaging card/panel designs for story steps + - Better use of colors for different step types (story, action, choice) + - Add subtle animations/transitions between steps + - Enhance button styling (hover states, active states, disabled states) + +- [ ] **Story presentation** + - More immersive story text formatting + - Better visual separation between story and instructions + - Add instructor avatar or themed visual elements + - Consider different visual themes per arc + +#### Action Button States +- [ ] **Clear visual feedback** + - Distinct hover states + - Clear disabled state (grayed out with reason) + - Loading/processing state for async actions + - Success state animation when completing actions + +- [ ] **Button labeling** + - More descriptive button text (e.g., "Continue to Next Challenge" vs "Continue") + - Show what happens next on buttons when possible + - Display time remaining on timed action buttons + +### Feature Enhancements + +#### Library Tagging Verification (Level 2) +- [ ] **Create new action type: `library-tag-verification`** + - Parameters: + ```javascript + { + type: 'library-tag-verification', + params: { + requiredImages: 5, + requiredVideos: 5, + suggestedTags: ['amateur', 'solo', 'pov'] + } + } + ``` + +- [ ] **Build in-game tagging interface** + - Display user's library files (images and videos separately) + - File preview thumbnails + - Tag input field with suggestions + - Apply tags to multiple files at once + +- [ ] **Live progress tracking** + - Counter display: "Images tagged: 3/5 | Videos tagged: 2/5" + - Visual progress bars for each type + - Green checkmark when threshold reached + - Disable "Complete" button until both thresholds met + +- [ ] **Integration with libraryManager** + - Use existing `tagFile()` and `tagDirectory()` methods + - Sync tags to localStorage + - Validate minimum tags applied before allowing progression + +#### General Quality of Life +- [ ] **Keyboard shortcuts** + - Space/Enter to continue on story steps + - ESC to open quit confirmation + - Number keys for multiple choice selections + +- [ ] **Session persistence** + - Save mid-level progress (not just level completion) + - Resume option if session interrupted + - "Last played" timestamp display + +- [ ] **Progress indicators** + - Show "Step X of Y" in scenarios with multiple steps + - Arc progress bar (e.g., "Foundation Arc: 3/5 levels complete") + - Overall campaign progress percentage + +### Accessibility Improvements +- [ ] **Screen reader support** + - Proper ARIA labels on all interactive elements + - Announce step changes to screen readers + - Keyboard navigation for all features + +- [ ] **Visual accessibility** + - High contrast mode option + - Adjustable text size + - Color-blind friendly color schemes + +- [ ] **Audio accessibility** + - TTS volume controls more prominent + - Option to adjust TTS speed + - Visual captions for TTS announcements + +### Performance Optimizations +- [ ] **Reduce load times** + - Lazy load level data (only load current + next 2 levels) + - Optimize scenario step rendering + - Cache frequently used images/assets + +- [ ] **Smooth transitions** + - Add loading states between levels + - Prevent UI flicker during step changes + - Optimize video player initialization + +### Bug Fixes & Edge Cases +- [ ] **Error handling** + - Graceful fallback if webcam unavailable + - Better messaging if video library empty + - Handle missing preferences gracefully + +- [ ] **Edge cases** + - What happens if user completes level without saving? + - Handle browser refresh mid-level + - Prevent double-clicking completion buttons + +--- + +## 📂 Files to Modify + +### Primary Files: +- `training-academy.html` - UI improvements, new action handler +- `src/features/tasks/interactiveTaskManager.js` - Library tag verification action +- `src/features/academy/libraryManager.js` - Tagging interface integration +- `src/styles/academy-ui.css` - Visual enhancements + +### Supporting Files: +- `src/features/academy/academyUI.js` - Progress indicators +- `src/data/modes/trainingGameData.js` - Update Level 2 to use new tagging action +- `src/features/ui/flashMessageManager.js` - Better user feedback + +--- + +## 🎯 Success Criteria + +**Phase 8 Complete When:** +1. UI/UX improvements implemented and tested +2. Library tagging verification working in-game +3. All quality of life features functional +4. Accessibility requirements met +5. Performance optimizations applied +6. Bug fixes verified +7. User testing shows improved experience + +--- + +## 📝 Testing Checklist + +### UI/UX Testing: +- [ ] All scenario steps render with improved styling +- [ ] Button states clearly visible and functional +- [ ] Transitions smooth and performant +- [ ] Story text engaging and well-formatted + +### Feature Testing: +- [ ] Library tagging verification tracks correctly +- [ ] Both image and video thresholds work +- [ ] Progress saves and persists +- [ ] Keyboard shortcuts functional + +### Accessibility Testing: +- [ ] Screen reader announces all changes +- [ ] Full keyboard navigation works +- [ ] High contrast mode readable +- [ ] TTS controls accessible + +### Performance Testing: +- [ ] Levels load quickly +- [ ] No UI lag during step transitions +- [ ] Video playback smooth +- [ ] Memory usage acceptable + +--- + +## 🚀 Implementation Priority + +**High Priority** (Do First): +1. UI/UX improvements (most visible impact) +2. Library tagging verification (core feature gap) +3. Button state improvements (user feedback) + +**Medium Priority** (Do Second): +1. Keyboard shortcuts +2. Progress indicators +3. Session persistence + +**Low Priority** (Polish): +1. Accessibility enhancements +2. Performance optimizations +3. Advanced visual theming + +--- + +## 💡 Future Considerations + +Items to consider for post-Phase 8: +- Custom instructor personas (different voices/styles) +- Achievement system for completing challenges +- Leaderboard/community features +- Custom level editor +- Mobile responsiveness +- Dark/light theme toggle +- Export/import progress data diff --git a/feedback.txt b/feedback.txt index dd654c5..89c212c 100644 --- a/feedback.txt +++ b/feedback.txt @@ -17,4 +17,9 @@ Thoughts so far: I'm liking it, I'm using it a couple times every gooning session, I can def see improvements in the gaming tracking (maybe some more achievements) I haven't gone through ALL functions but will keep you updated... -Also think would be interesting to have a kind of "Story Mode", like narrative driven gooning... Sounds fun, would love to help here too \ No newline at end of file +Also think would be interesting to have a kind of "Story Mode", like narrative driven gooning... Sounds fun, would love to help here too + + + + +I would like to lift and shift all the library code from index.html to it's own page(library.html). Please mirror it to all the other pages with a header that matches the style and all the css variables to ensure the theme is continuous throughout. \ No newline at end of file diff --git a/index.html b/index.html index b3eaa2a..ce87d0c 100644 --- a/index.html +++ b/index.html @@ -196,6 +196,22 @@ Library + + + + @@ -894,6 +910,10 @@ + + + + @@ -3424,6 +3444,31 @@ // Initialize backup system initializeBackupSystem(); + + // Set up global localStorage quota handler + const originalSetItem = localStorage.setItem.bind(localStorage); + localStorage.setItem = function(key, value) { + try { + originalSetItem(key, value); + } catch (error) { + if (error.name === 'QuotaExceededError') { + console.error('🚨 LocalStorage quota exceeded! Performing emergency cleanup...'); + if (window.backupManager) { + window.backupManager.performEmergencyCleanup(); + } + // Try again after cleanup + try { + originalSetItem(key, value); + console.log('✅ Save succeeded after cleanup'); + } catch (retryError) { + console.error('❌ Save failed even after cleanup:', retryError); + alert('⚠️ Storage is full! Photo data has been cleared. Please restart the app.'); + } + } else { + throw error; + } + } + }; } // Set up video management button (only once) const videoManageBtn = document.getElementById('manage-video-btn'); if (videoManageBtn && !videoManageBtn.hasAttribute('data-handler-attached')) { diff --git a/scripts/create-distribution.bat b/scripts/create-distribution.bat index a8b9d85..9736ff6 100644 --- a/scripts/create-distribution.bat +++ b/scripts/create-distribution.bat @@ -38,9 +38,9 @@ copy package.json "%OUTPUT_DIR%\" :: Copy documentation echo 📚 Copying documentation... copy README.md "%OUTPUT_DIR%\" -copy TESTER_GUIDE.md "%OUTPUT_DIR%\" -copy INSTALLATION_GUIDE.md "%OUTPUT_DIR%\" -copy README-DESKTOP.md "%OUTPUT_DIR%\" +@REM copy TESTER_GUIDE.md "%OUTPUT_DIR%\" +@REM copy INSTALLATION_GUIDE.md "%OUTPUT_DIR%\" +@REM copy README-DESKTOP.md "%OUTPUT_DIR%\" :: Copy setup scripts echo 🔧 Copying setup scripts... @@ -58,11 +58,11 @@ xcopy assets "%OUTPUT_DIR%\assets\" /e /i /q :: Copy empty directories for user content echo 📁 Creating user content directories... -mkdir "%OUTPUT_DIR%\images" -mkdir "%OUTPUT_DIR%\images\tasks" -mkdir "%OUTPUT_DIR%\images\consequences" +mkdir "%OUTPUT_DIR%\photos" +mkdir "%OUTPUT_DIR%\photos\captured" mkdir "%OUTPUT_DIR%\audio" mkdir "%OUTPUT_DIR%\videos" +mkdir "%OUTPUT_DIR%\videos\recorded" mkdir "%OUTPUT_DIR%\backups" :: Copy sample audio (if exists) @@ -71,29 +71,11 @@ if exist audio\*.mp3 ( xcopy audio "%OUTPUT_DIR%\audio\" /e /i /q /y ) -:: Create placeholder files -echo 📝 Creating placeholder files... -echo # User Task Images > "%OUTPUT_DIR%\images\tasks\README.md" -echo Upload your custom task images here. Supported formats: JPG, PNG, WebP >> "%OUTPUT_DIR%\images\tasks\README.md" -echo Maximum 50 images, recommended resolution: 1600x1200 >> "%OUTPUT_DIR%\images\tasks\README.md" - -echo # User Consequence Images > "%OUTPUT_DIR%\images\consequences\README.md" -echo Upload your custom consequence images here. Supported formats: JPG, PNG, WebP >> "%OUTPUT_DIR%\images\consequences\README.md" -echo These images are used for punishment scenarios. >> "%OUTPUT_DIR%\images\consequences\README.md" - -echo # Background Music > "%OUTPUT_DIR%\audio\README.md" -echo Place your background music files here. Supported formats: MP3, WAV, OGG >> "%OUTPUT_DIR%\audio\README.md" -echo Files will be automatically detected and added to the playlist. >> "%OUTPUT_DIR%\audio\README.md" - -echo # Video Directory > "%OUTPUT_DIR%\videos\README.md" -echo Link external video directories here or place video files directly. >> "%OUTPUT_DIR%\videos\README.md" -echo Supported formats: MP4, WebM, AVI, MOV >> "%OUTPUT_DIR%\videos\README.md" -echo For best performance, use MP4 format with H.264 codec. >> "%OUTPUT_DIR%\videos\README.md" :: Create distribution info file echo 📋 Creating distribution info... echo # Gooner Training Academy - Distribution Info > "%OUTPUT_DIR%\DISTRIBUTION_INFO.txt" -echo Version: 4.0 Beta >> "%OUTPUT_DIR%\DISTRIBUTION_INFO.txt" +echo Version: 4.1 Beta >> "%OUTPUT_DIR%\DISTRIBUTION_INFO.txt" echo Build Date: %BUILD_DATE% >> "%OUTPUT_DIR%\DISTRIBUTION_INFO.txt" echo Package Type: Beta Testing Build >> "%OUTPUT_DIR%\DISTRIBUTION_INFO.txt" echo. >> "%OUTPUT_DIR%\DISTRIBUTION_INFO.txt" diff --git a/src/data/modes/dressUpGameData.js b/src/data/modes/dressUpGameData.js index 0910b3e..406dbdf 100644 --- a/src/data/modes/dressUpGameData.js +++ b/src/data/modes/dressUpGameData.js @@ -1,292 +1,296 @@ /** * Dress-Up/Photography Game Mode Data - * Webcam photography and dressing challenges + * Inventory-based progressive photo challenges */ const dressUpGameData = { // Photography and dress-up tasks - mainTasks: [ - { - id: 'photo-session-1', - text: "Basic Photo Session", - difficulty: "Easy", - interactiveType: "photo-challenge", - story: "Take photos of yourself following the specified requirements.", - photoRequirements: { - count: 3, - poses: ["standing", "sitting", "profile"], - timer: 30 - } - }, - { - id: 'outfit-challenge-1', - text: "Outfit Coordination Challenge", - difficulty: "Medium", - interactiveType: "choice-challenge", - story: "Choose and model different outfit combinations.", - choices: [ - { text: "Casual wear", value: "casual", points: 10 }, - { text: "Formal attire", value: "formal", points: 15 }, - { text: "Creative costume", value: "creative", points: 20 } - ] - }, - { - id: 'pose-sequence-1', - text: "Pose Sequence Challenge", - difficulty: "Hard", - interactiveType: "photo-challenge", - story: "Execute a sequence of poses for a professional photo shoot.", - photoRequirements: { - count: 6, - poses: ["elegant", "playful", "serious", "dynamic", "artistic", "confident"], - timer: 45 - } - } - ], + mainTasks: [], - // Dress-up scenarios + // Consequence tasks for dress-up mode + consequenceTasks: [], + + // Inventory-based progression scenario scenarios: [ { - id: 'scenario-dress-up-photo', - text: "Sissy Dress-Up Photo Session", - difficulty: "Medium", + id: 'scenario-inventory-progression', + text: "Personal Transformation Photo Journey", + difficulty: "Variable", interactiveType: "scenario-adventure", interactiveData: { - title: "Feminization Photography Studio", + title: "Inventory-Based Photo Transformation", steps: { start: { type: 'choice', - mood: 'dominant', - story: "You've been brought to a private studio for a special photo session. The photographer looks you up and down with a smirk. 'Today we're going to transform you into the perfect little sissy and document every humiliating moment. Which type of feminization session should we start with?'", + mood: 'introduction', + story: "Welcome to your personalized transformation photo session. I'll guide you through a progressive photo journey tailored to what you have available. First, I need to know what items you have at your disposal. Be honest - this determines your entire experience.", choices: [ { - text: "Forced feminization makeover", - type: "feminization", - preview: "Complete transformation into a sissy", - nextStep: "feminization_path" - }, - { - text: "Humiliating sissy maid outfit", - type: "maid", - preview: "Degrading maid costume and poses", - nextStep: "maid_path" - }, - { - text: "Slutty schoolgirl transformation", - type: "schoolgirl", - preview: "Inappropriate schoolgirl outfit and poses", - nextStep: "schoolgirl_path" - }, - { - text: "Bimbo princess dress-up", - type: "bimbo", - preview: "Over-the-top feminine and degrading", - nextStep: "bimbo_path" + text: "Begin inventory questionnaire", + nextStep: "questionnaire" } ] }, - feminization_path: { - type: 'action', - mood: 'humiliating', - story: "The photographer forces you into a frilly pink dress, applies makeup to your face, and puts a blonde wig on your head. 'Look at what a pathetic little sissy you make! Edge while I take pictures of your humiliation. The more aroused you get, the more feminine and submissive you'll look in the photos.'", - actionText: "Edge while being feminized and photographed", - duration: 240, - nextStep: "feminization_progression" + + questionnaire: { + type: 'inventory-check', + mood: 'assessment', + story: "Let's assess what you have available. Select the appropriate option for each item category.", + inventoryCategories: { + clothing: { + title: "👗 Clothing & Feminization Items", + items: { + panties: { label: 'Panties', options: ['none', 'basic', 'sexy', 'multiple'] }, + bras: { label: 'Bras', options: ['none', 'sports', 'regular', 'sexy', 'multiple'] }, + dresses: { label: 'Dresses', options: ['none', 'casual', 'slutty', 'multiple'] }, + skirts: { label: 'Skirts', options: ['none', 'basic', 'mini', 'micro', 'multiple'] }, + pantyhose: { label: 'Pantyhose/Stockings', options: ['none', 'nude', 'fishnet', 'multiple'] }, + heels: { label: 'Heels/Shoes', options: ['none', 'flats', 'heels', 'platforms'] }, + wigs: { label: 'Wigs', options: ['none', 'short', 'long', 'colored'] }, + lingerie: { label: 'Lingerie Sets', options: ['none', 'basic', 'sexy', 'extreme'] } + } + }, + accessories: { + title: "💄 Makeup & Accessories", + items: { + makeup: { label: 'Makeup Kit', options: ['none', 'basic', 'full'] }, + jewelry: { label: 'Jewelry', options: ['none', 'basic', 'feminine', 'collar'] }, + nailPolish: { label: 'Nail Polish', options: ['none', 'basic', 'colors'] } + } + }, + toys: { + title: "🔞 Toys & Restraints", + items: { + dildos: { label: 'Dildos', options: ['none', 'small', 'medium', 'large', 'multiple'] }, + plugs: { label: 'Butt Plugs', options: ['none', 'small', 'medium', 'large', 'tail'] }, + chastity: { label: 'Chastity Device', options: ['none', 'cage', 'belt'] }, + restraints: { label: 'Restraints', options: ['none', 'cuffs', 'rope', 'spreader'] }, + gags: { label: 'Gags', options: ['none', 'ball', 'ring'] }, + nippleClamps: { label: 'Nipple Clamps', options: ['none', 'basic', 'weighted', 'chain'] } + } + }, + environment: { + title: "📸 Setup & Environment", + items: { + mirror: { label: 'Mirror Available', type: 'boolean' }, + fullMirror: { label: 'Full-Length Mirror', type: 'boolean' }, + privateSpace: { label: 'Private Space', type: 'boolean' }, + phoneStand: { label: 'Phone/Camera Stand', type: 'boolean' } + } + } + }, + nextStep: "inventory_summary" }, - maid_path: { - type: 'action', - mood: 'degrading', - story: "The photographer hands you a skimpy maid outfit with a short frilly skirt. 'Put this on, sissy maid. You're going to pose like the submissive little servant you are. Edge while I photograph your humiliation. Show me how pathetic you look in that outfit.'", - actionText: "Edge while posing as a degraded sissy maid", - duration: 300, - nextStep: "maid_progression" - }, - schoolgirl_path: { - type: 'action', - mood: 'inappropriate', - story: "The photographer tosses you a slutty schoolgirl outfit - tiny plaid skirt, tight white shirt, and pigtails. 'Time to play dress-up, little girl. You're going to pose like the naughty schoolgirl slut you are. Edge while I capture your shame.'", - actionText: "Edge while posing as a slutty schoolgirl", - duration: 180, - nextStep: "schoolgirl_progression" - }, - bimbo_path: { - type: 'action', - mood: 'bimbo', - story: "The photographer pulls out the most degrading outfit yet - a hot pink mini dress, massive fake breasts, blonde bimbo wig, and platform heels. 'Time to complete your transformation into a brainless bimbo slut. Edge while I photograph how pathetic and desperate you look. Show me what a dumb little bimbo you are.'", - actionText: "Edge while posing as a humiliated bimbo", - duration: 360, - nextStep: "bimbo_progression" - }, - feminization_progression: { - type: 'choice', - mood: 'sissy_humiliation', - story: "The photographer reviews the humiliating feminization photos. 'Look at these pictures - you make such a pathetic little sissy! The camera captured every moment of your shame. Ready to take it further?'", + + inventory_summary: { + type: 'path-generation', + mood: 'planning', + story: "Processing your inventory... Calculating your transformation tier...", choices: [ { - text: "Take sissy humiliation photos now", - type: "photography", - preview: "Capture your feminized shame", - nextStep: "feminization_photo_session" + text: "Begin my personalized photo journey", + nextStep: "challenge_1" }, { - text: "More extreme feminization", - type: "extreme_feminization", - preview: "Push your sissy transformation further", - nextStep: "extreme_feminization_path" + text: "Adjust my inventory answers", + nextStep: "questionnaire" } ] }, - maid_progression: { - type: 'choice', - mood: 'maid_humiliation', - story: "The photographer laughs at the photos of you in the maid outfit. 'Such a pathetic little servant! You look so degraded and humiliated. But maybe we should explore other forms of humiliation too...'", - choices: [ - { - text: "Take maid humiliation photos now", - type: "photography", - preview: "Document your maid degradation", - nextStep: "maid_photo_session" - }, - { - text: "Force you to clean while dressed as maid", - type: "cleaning", - preview: "Humiliating cleaning tasks", - nextStep: "cleaning_path" - } - ] - }, - schoolgirl_progression: { - type: 'choice', - mood: 'schoolgirl_shame', - story: "The photographer reviews the slutty schoolgirl photos. 'Look how inappropriate you look! Such a naughty little schoolgirl slut. But I think we can make you even more shameful...'", - choices: [ - { - text: "Take slutty schoolgirl photos now", - type: "photography", - preview: "Capture your schoolgirl shame", - nextStep: "schoolgirl_photo_session" - }, - { - text: "Pose in even more inappropriate positions", - type: "inappropriate", - preview: "More degrading schoolgirl poses", - nextStep: "inappropriate_path" - } - ] - }, - bimbo_progression: { - type: 'choice', - mood: 'bimbo_degradation', - story: "The photographer can't stop laughing at how ridiculous you look as a bimbo. 'You're the perfect brainless slut! So dumb and desperate. But maybe we can combine this with other humiliating styles...'", - choices: [ - { - text: "Take bimbo humiliation photos now", - type: "photography", - preview: "Capture your bimbo transformation", - nextStep: "bimbo_photo_session" - }, - { - text: "Force you to act like a brainless bimbo", - type: "bimbo_act", - preview: "Humiliating bimbo behavior", - nextStep: "bimbo_act_path" - } - ] - }, - feminization_photo_session: { + + // Photo challenges will be dynamically generated based on tier + // Tier 1: challenge_1 through challenge_5 + // Tier 2: challenge_1 through challenge_10 + // Tier 3: challenge_1 through challenge_15 + // Tier 4: challenge_1 through challenge_20 + // Tier 5: challenge_1 through challenge_25 + + // These will be created dynamically by the system + // Each challenge follows this structure: + /* + challenge_X: { + type: 'photo-verification', + mood: 'progressive', + story: "Generated based on tier, items, and progression", + photoRequirements: { + items: ['panties', 'bra'], // Required items + pose: 'category_name', // Pose category + edging: false, // Whether to edge + count: 3 // Number of photos + }, + nextStep: "challenge_X+1" or "tier_X_ending" + } + */ + + // Tier 1 ending (5 photos) + tier_1_ending: { type: 'ending', - mood: 'sissy_documented', - story: "The photographer reviews the humiliating sissy photos. 'Perfect shots! Every photo captures your feminization and humiliation beautifully. You're documented as a complete sissy now.'", - endingText: "Feminization photography completed. Final state: Arousal HIGH, Control VARIABLE. Your sissy transformation has been documented.", - outcome: "documented_sissy" + mood: 'completion', + endingTitle: "🩲 CERTIFICATE OF BASIC EXPOSURE", + endingText: ` +
+

🩲 CERTIFICATE OF BASIC EXPOSURE 🩲

+ +
+

+ EXPOSED AND
+ DOCUMENTED +

+ +
+

📸 Photos Taken: 5

+

👗 Items Used:

+
+
+ +

+ Final State: EXPOSED BEGINNER +

+ +

+ Your journey has been documented. Consider acquiring more items to unlock higher tiers. +

+
+
+ `, + outcome: "tier_1_complete" }, - maid_photo_session: { + + // Tier 2 ending (10 photos) + tier_2_ending: { type: 'ending', - mood: 'maid_documented', - story: "The photographer looks through the degrading maid photos. 'Excellent! These photos show what a pathetic little servant you are. Your humiliation is perfectly captured.'", - endingText: "Maid humiliation photography completed. Final state: Arousal HIGH, Control VARIABLE. Your maid degradation has been documented.", - outcome: "documented_maid" + mood: 'completion', + endingTitle: "👗 CERTIFICATE OF FEMINIZATION BEGINNER", + endingText: ` +
+

👗 CERTIFICATE OF FEMINIZATION BEGINNER 👗

+ +
+

+ FEMINIZATION JOURNEY
+ DOCUMENTED +

+ +
+

📸 Photos Taken: 10

+

👗 Items Used:

+
+
+ +

+ Final State: FEMINIZATION INITIATED +

+ +

+ You've taken your first steps into feminization and it's all documented. +

+
+
+ `, + outcome: "tier_2_complete" }, - schoolgirl_photo_session: { + + // Tier 3 ending (15 photos) + tier_3_ending: { type: 'ending', - mood: 'schoolgirl_documented', - story: "The photographer reviews the slutty schoolgirl photos. 'Incredible shots! You look so inappropriate and shameful. Every photo captures your schoolgirl slut transformation.'", - endingText: "Schoolgirl photography completed. Final state: Arousal HIGH, Control VARIABLE. Your schoolgirl shame has been documented.", - outcome: "documented_schoolgirl" + mood: 'completion', + endingTitle: "🎀 CERTIFICATE OF COMPLETE SISSY TRANSFORMATION", + endingText: ` +
+

🎀 CERTIFICATE OF COMPLETE SISSY TRANSFORMATION 🎀

+ +
+

+ COMPLETE SISSY
+ TRANSFORMATION ACHIEVED +

+ +
+

📸 Photos Taken: 15

+

👗 Items Used:

+
+
+ +

+ Final State: FULLY FEMINIZED SISSY +

+ +

+ Your complete transformation into a sissy has been thoroughly documented. +

+
+
+ `, + outcome: "tier_3_complete" }, - bimbo_photo_session: { + + // Tier 4 ending (20 photos) + tier_4_ending: { type: 'ending', - mood: 'bimbo_documented', - story: "The photographer can't stop laughing at the bimbo photos. 'These are perfect! You look like such a brainless slut. Every photo captures your complete bimbo transformation.'", - endingText: "Bimbo photography completed. Final state: Arousal HIGH, Control VARIABLE. Your bimbo transformation has been documented.", - outcome: "documented_bimbo" + mood: 'completion', + endingTitle: "🔞 CERTIFICATE OF TOY INTEGRATION MASTER", + endingText: ` +
+

🔞 CERTIFICATE OF TOY INTEGRATION MASTER 🔞

+ +
+

+ DEGRADATION WITH TOYS
+ DOCUMENTED +

+ +
+

📸 Photos Taken: 20

+

👗 Items Used:

+
+
+ +

+ Final State: TOY-TRAINED SISSY SLUT +

+ +

+ Your feminization combined with toy usage has been completely documented. +

+
+
+ `, + outcome: "tier_4_complete" }, - extreme_feminization_path: { - type: 'action', - mood: 'extreme_humiliation', - story: "The photographer pulls out even more degrading feminine items - a frilly baby doll dress, excessive makeup, and humiliating accessories. 'Time to push your feminization to the extreme! You're going to become the most pathetic sissy possible. Edge while I document your complete transformation into a humiliated sissy slut.'", - actionText: "Edge while undergoing extreme feminization", - duration: 300, - nextStep: "extreme_feminization_completion" - }, - extreme_feminization_completion: { + + // Tier 5 ending (25 photos) + tier_5_ending: { type: 'ending', - mood: 'extreme_sissy_documented', - story: "The photographer reviews the extreme feminization photos with delight. 'Absolutely perfect! These photos show your complete transformation into the most pathetic sissy possible. Every shot captures your extreme feminization and total humiliation.'", - endingText: "Extreme feminization completed. You have been transformed into the ultimate sissy and it's all documented.", - outcome: "extreme_sissy_documented" - }, - cleaning_path: { - type: 'action', - mood: 'maid_degradation', - story: "The photographer hands you cleaning supplies. 'Time to put that maid outfit to use! You're going to clean this studio while I photograph your humiliation. Edge while you work like the pathetic little servant you are.'", - actionText: "Edge while performing humiliating cleaning tasks", - duration: 240, - nextStep: "cleaning_completion" - }, - cleaning_completion: { - type: 'ending', - mood: 'maid_servant_documented', - story: "The photographer laughs at the photos of you cleaning while dressed as a maid. 'Perfect! These photos show what a degraded little servant you are. Your humiliation while doing menial labor is beautifully captured.'", - endingText: "Maid cleaning session completed. Your degradation as a servant has been documented.", - outcome: "maid_servant_documented" - }, - inappropriate_path: { - type: 'action', - mood: 'schoolgirl_degradation', - story: "The photographer directs you into increasingly inappropriate and shameful poses. 'Spread your legs wider! Bend over more! Show me how slutty you can be in that schoolgirl outfit. Edge while I capture every shameful moment.'", - actionText: "Edge while posing in degrading schoolgirl positions", - duration: 180, - nextStep: "inappropriate_completion" - }, - inappropriate_completion: { - type: 'ending', - mood: 'schoolgirl_slut_documented', - story: "The photographer reviews the inappropriate schoolgirl photos with satisfaction. 'These are incredibly shameful! Every photo captures how much of a slutty schoolgirl you are. Your inappropriate behavior is perfectly documented.'", - endingText: "Inappropriate schoolgirl session completed. Final state: Arousal HIGH, Control VARIABLE. Your shameful schoolgirl behavior has been documented.", - outcome: "schoolgirl_slut_documented" - }, - bimbo_act_path: { - type: 'action', - mood: 'bimbo_behavior', - story: "The photographer forces you to act like a brainless bimbo. 'Talk like a dumb slut! Giggle constantly! Show me how stupid you can be! Edge while acting like the brainless bimbo you've become while I photograph your pathetic behavior.'", - actionText: "Edge while acting like a brainless bimbo", - duration: 300, - nextStep: "bimbo_act_completion" - }, - bimbo_act_completion: { - type: 'ending', - mood: 'bimbo_behavior_documented', - story: "The photographer can't stop laughing at the photos of you acting like a brainless bimbo. 'These are hilarious! Every photo captures how stupid and desperate you are. Your complete bimbo transformation is perfectly documented.'", - endingText: "Bimbo behavior session completed. Your brainless bimbo behavior has been documented.", - outcome: "bimbo_behavior_documented" - }, - completion: { - type: 'ending', - mood: 'satisfied', - story: "The photographer reviews the humiliating photos with satisfaction. 'Perfect! These photos capture your complete transformation and degradation. You're now documented as the sissy you truly are.'", - endingText: "Photo session complete. Your feminization has been permanently documented.", - outcome: "feminized_documented" + mood: 'completion', + endingTitle: "⛓️ CERTIFICATE OF ULTIMATE SISSY SLUT", + endingText: ` +
+

⛓️ CERTIFICATE OF ULTIMATE SISSY SLUT ⛓️

+ +
+

+ ULTIMATE TRANSFORMATION:
+ COMPLETE DEGRADATION +

+ +
+

📸 Photos Taken: 25

+

👗 Full Collection Used:

+
+

🏆 EXTREME COLLECTION MASTER

+
+ +

+ Final State: ULTIMATE DEGRADED SISSY +

+ +

+ Your complete transformation and degradation using every item has been permanently documented. You are the ultimate sissy slut. +

+
+
+ `, + outcome: "tier_5_complete" } } } @@ -295,18 +299,10 @@ const dressUpGameData = { // Configuration for dress-up mode config: { - photoSettings: { - defaultTimer: 30, - maxPhotos: 10, - qualityRequirements: { - lighting: "good", - focus: "sharp", - composition: "centered" - } - }, - themes: ["elegant", "playful", "artistic", "professional", "creative"], - mood: "creative", - theme: "expression" + inventoryBased: true, + dynamicProgression: true, + mood: "transformation", + theme: "personalization" } }; diff --git a/src/data/modes/trainingGameData.js b/src/data/modes/trainingGameData.js index df36f54..2451e20 100644 --- a/src/data/modes/trainingGameData.js +++ b/src/data/modes/trainingGameData.js @@ -437,6 +437,1001 @@ const trainingGameData = { */ ], + // ======================================== + // ACADEMY CAMPAIGN SCENARIOS (Levels 1-30) + // ======================================== + + academyScenarios: { + // FOUNDATION ARC (Levels 1-5) + level1: { + id: 'academy-level-1', + name: 'Edge Training 101', + arc: 'Foundation', + level: 1, + duration: 300, // 5 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 1: Edge Training 101', + steps: { + start: { + type: 'story', + mood: 'welcoming', + story: 'Welcome to The Academy, aspiring gooner. I am your instructor, and I will guide your transformation. Today, we begin with the foundation of all gooning: the edge. You will learn to ride the wave of pleasure without release. Are you ready to begin your journey?', + nextStep: 'intro_complete' + }, + intro_complete: { + type: 'action', + mood: 'instructional', + story: 'Your first lesson is simple: edge 5 times. Stroke yourself to the very brink, feel that rush of pleasure, then stop. Hold yourself there. Feel it pulsing, demanding release. But you will not give in. This is control. This is the beginning.', + interactiveType: 'edge', + params: { count: 5, instruction: 'Edge 5 times - slowly and deliberately' }, + nextStep: 'first_edges_done' + }, + first_edges_done: { + type: 'story', + mood: 'praising', + story: 'Good. Very good. You felt it, didn\'t you? That moment where your body screamed for release, but your mind held firm. That is power. That is what we are building here. You have completed your first training session. Level 2 awaits when you\'re ready.', + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'satisfied', + story: '✅ Level 1 Complete - You have taken your first steps into The Academy.', + outcome: 'level1_complete' + } + } + } + }, + + level2: { + id: 'academy-level-2', + name: 'Rhythm & Control', + arc: 'Foundation', + level: 2, + duration: 600, // 10 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 2: Rhythm & Control', + steps: { + start: { + type: 'story', + mood: 'instructional', + story: 'Welcome back. You\'ve proven you can edge. Now we add rhythm. Gooning isn\'t just about edging - it\'s about finding your flow, your pace, your perfect stroking cadence. We will also begin building your library, the collection that will fuel your transformation.', + nextStep: 'rhythm_intro' + }, + rhythm_intro: { + type: 'action', + mood: 'focused', + story: 'Follow the rhythm pattern: slow... fast... slow. Let the metronome guide your hand. Feel how changing pace builds different sensations. Slow is teasing. Fast is intense. Together, they create perfect edging rhythm.', + interactiveType: 'rhythm', + params: { pattern: 'slow-fast-slow', duration: 180 }, + nextStep: 'library_time' + }, + library_time: { + type: 'action', + mood: 'practical', + story: 'Now, let\'s build your library. Add a directory of content to The Academy system. This collection will grow with you, becoming more organized and powerful as you progress. A gooner with a curated library is a gooner with focus.', + interactiveType: 'add-library-directory', + params: { + suggestedTags: ['amateur', 'solo'] + }, + nextStep: 'final_edges' + }, + final_edges: { + type: 'action', + mood: 'encouraging', + story: 'Excellent. Your library is growing. Now edge 10 times to cement this lesson. Feel how the rhythm you learned makes edging smoother, more natural. This is progress.', + interactiveType: 'edge', + params: { count: 10, instruction: 'Edge 10 times using your new rhythm' }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'satisfied', + story: '✅ Level 2 Complete - Your rhythm improves. Your library grows. You are evolving.', + outcome: 'level2_complete' + } + } + } + }, + + level3: { + id: 'academy-level-3', + name: 'Visual Immersion', + arc: 'Foundation', + level: 3, + duration: 900, // 15 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 3: Visual Immersion', + steps: { + start: { + type: 'story', + mood: 'anticipatory', + story: 'You have learned edges. You have learned rhythm. Now we add the third element: visual stimulation. Porn is not a distraction - it is fuel. It is the catalyst that transforms simple masturbation into gooning. Let me show you.', + nextStep: 'video_start' + }, + video_start: { + type: 'action', + mood: 'intense', + story: 'I am starting a video from your library. Watch it. Let it fill your vision. Let it fill your mind. This is what you stroke to now. Not fantasy. Not imagination. Reality captured on screen.', + interactiveType: 'video-start', + params: { player: 'focus', tags: ['amateur'] }, + nextStep: 'tagging_task' + }, + tagging_task: { + type: 'action', + mood: 'practical', + story: 'While you watch, you will learn organization. Tag at least 10 files in your library. Mark them with what they contain: POV? Blowjob? Riding? A organized library is a powerful library. Tag them while you stroke.', + interactiveType: 'tag-files', + params: { + minFiles: 10, + suggestedTags: ['pov', 'blowjob', 'riding', 'amateur'] + }, + nextStep: 'visual_edges' + }, + visual_edges: { + type: 'action', + mood: 'commanding', + story: 'Good. Now edge while watching. Feel the difference. The video makes it so much more intense, doesn\'t it? This is why gooners worship porn. It amplifies everything.', + interactiveType: 'edge', + params: { + duration: 300, // 5 minutes of edging + instruction: 'Edge and stroke while watching the video', + keepVideoPlaying: true // Signal to keep video active + }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'satisfied', + story: '✅ Level 3 Complete - You have unlocked visual training. Porn is your companion now.', + outcome: 'level3_complete' + } + } + } + }, + + level4: { + id: 'academy-level-4', + name: 'Multi-Tasking Challenge', + arc: 'Foundation', + level: 4, + duration: 1200, // 20 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 4: Multi-Tasking Challenge', + steps: { + start: { + type: 'story', + mood: 'challenging', + story: 'You are progressing well. Now we test if you can combine what you\'ve learned. Rhythm + Video + Edges. All at once. This is where casual masturbators fail, but gooners thrive. Show me you can handle it.', + nextStep: 'everything_at_once' + }, + everything_at_once: { + type: 'action', + mood: 'intense', + story: 'Video starting. Now follow this rhythm: FAST... slow... FAST. While watching. While edging. Your brain is being rewired to handle multiple streams of pleasure at once. This is gooner multitasking.', + interactiveType: 'rhythm', + params: { pattern: 'fast-slow-fast', duration: 240 }, + nextStep: 'sustained_edges' + }, + sustained_edges: { + type: 'action', + mood: 'demanding', + story: 'Don\'t stop the video. Don\'t lose the rhythm. Now edge 20 times. I know it\'s hard. I know your hand is tired. But gooners don\'t quit. Gooners push through. Edge. Again. AGAIN.', + interactiveType: 'edge', + params: { count: 20, instruction: 'Edge 20 times - maintain rhythm and focus' }, + nextStep: 'almost_there' + }, + almost_there: { + type: 'story', + mood: 'encouraging', + story: 'Keep going... faster... you\'re doing it. You\'re combining all the skills. This is what a gooner looks like - pumping, watching, edging, completely immersed. Almost there...', + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'triumphant', + story: '✅ Level 4 Complete - You can multi-task like a true gooner. Foundation Arc nearly complete.', + outcome: 'level4_complete' + } + } + } + }, + + level5: { + id: 'academy-level-5', + name: 'Foundation Checkpoint', + arc: 'Foundation', + level: 5, + isCheckpoint: true, + duration: 1500, // 25 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 5: Foundation Checkpoint', + steps: { + start: { + type: 'story', + mood: 'ceremonial', + story: 'You have reached your first checkpoint. Levels 1-4 have taught you edges, rhythm, videos, and multi-tasking. Now we test everything together and update your preferences. This is a milestone. Prove you are ready for what comes next.', + nextStep: 'preference_update' + }, + preference_update: { + type: 'action', + mood: 'reflective', + story: 'First, tell The Academy what you crave. What themes excite you? What content makes you hardest? Update your preferences so your training can be personalized. This is your checkpoint configuration.', + interactiveType: 'update-preferences', + params: { checkpoint: 5 }, + nextStep: 'recap_training' + }, + recap_training: { + type: 'action', + mood: 'intense', + story: 'Now we recap all your training. Video on. Rhythm: steady. Edge as many times as you can in the time remaining. This is your Foundation Arc final exam. Show me you\'ve learned.', + interactiveType: 'free-edge-session', + params: { duration: 900, allowedFeatures: ['video', 'rhythm'] }, + nextStep: 'arc_complete' + }, + arc_complete: { + type: 'story', + mood: 'triumphant', + story: 'Foundation Arc Complete. You are no longer a beginner. You understand edges. You have rhythm. You use porn as fuel. Arc 2 awaits: Feature Discovery. Get ready - things are about to get much more intense.', + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'accomplished', + story: '✅🎯 Level 5 Complete - FOUNDATION ARC FINISHED. Feature Discovery begins next.', + outcome: 'level5_complete' + } + } + } + }, + + // FEATURE DISCOVERY ARC (Levels 6-10) + level6: { + id: 'academy-level-6', + name: 'The Observer', + arc: 'Feature Discovery', + level: 6, + duration: 1800, // 30 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 6: The Observer', + steps: { + start: { + type: 'story', + mood: 'intriguing', + story: 'Welcome to Feature Discovery. You have mastered the basics. Now we unlock advanced tools. Today: the webcam. You will watch yourself goon. Many resist this at first. But gooners embrace it. Let me show you why.', + nextStep: 'webcam_intro' + }, + webcam_intro: { + type: 'action', + mood: 'revealing', + story: 'Turn on your webcam. Position it so you can see yourself stroking. Look at yourself. Really look. That is who you are now. A gooner. Pumping. Edging. Addicted to porn. Embrace it.', + interactiveType: 'enable-webcam', + params: { instruction: 'Enable your webcam and watch yourself goon' }, + nextStep: 'mirror_edges' + }, + mirror_edges: { + type: 'action', + mood: 'intense', + story: 'Now edge 25 times while watching yourself. See your face flush. See your hand pumping. This is your reality. This is who you\'re becoming. And it feels good, doesn\'t it?', + interactiveType: 'edge', + params: { count: 25, instruction: 'Edge 25 times while watching yourself' }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'revelatory', + story: '✅ Level 6 Complete - WEBCAM UNLOCKED. Self-observation is now part of your training.', + outcome: 'level6_complete' + } + } + } + }, + + level7: { + id: 'academy-level-7', + name: 'Dual Focus', + arc: 'Feature Discovery', + level: 7, + duration: 2400, // 40 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 7: Dual Focus', + steps: { + start: { + type: 'story', + mood: 'escalating', + story: 'One video was good. But gooners don\'t settle for good. They crave MORE. Today you learn dual video mode: two streams of porn, simultaneously. Your brain will light up like never before.', + nextStep: 'dual_video_start' + }, + dual_video_start: { + type: 'action', + mood: 'overwhelming', + story: 'Starting dual video mode. Main screen + picture-in-picture. TWO feeds of porn. Your eyes won\'t know where to look. Your brain won\'t know what to process. That\'s the point. Sensory overload. Pure gooning.', + interactiveType: 'dual-video', + params: { mainVideo: 'focus', pipVideo: 'overlay', pipPosition: 'bottom-right' }, + nextStep: 'dual_edges' + }, + dual_edges: { + type: 'action', + mood: 'demanding', + story: 'Edge 30 times while both videos play. Try to watch both at once. Let your mind split between the two streams. This is advanced gooner technique - fractured attention, unified pleasure.', + interactiveType: 'edge', + params: { count: 30, instruction: 'Edge 30 times to dual video streams' }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'intense', + story: '✅ Level 7 Complete - DUAL VIDEO UNLOCKED. More screens = more stimulation.', + outcome: 'level7_complete' + } + } + } + }, + + level8: { + id: 'academy-level-8', + name: 'Vocal Commands', + arc: 'Feature Discovery', + level: 8, + duration: 3000, // 50 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 8: Vocal Commands', + steps: { + start: { + type: 'story', + mood: 'commanding', + story: 'You have eyes. You have hands. Now we add ears. Voice commands via text-to-speech will guide your edging. You will learn to obey the voice. To respond instantly. Gooners don\'t think - they obey.', + nextStep: 'tts_intro' + }, + tts_intro: { + type: 'action', + mood: 'authoritative', + story: 'Listen to the voice. It will tell you what to do. And you will do it. Without hesitation. This is training in obedience and responsiveness.', + interactiveType: 'tts-command', + params: { + text: 'Good gooner. You are learning to obey. Edge for me. Now.', + voice: 'feminine' + }, + nextStep: 'tts_edges' + }, + tts_edges: { + type: 'action', + mood: 'controlled', + story: 'The voice will count. You will edge each time it commands. 35 edges total. Listen. Obey. Edge.', + interactiveType: 'edge', + params: { count: 35, instruction: 'Edge 35 times on command' }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'authoritative', + story: '✅ Level 8 Complete - TTS UNLOCKED. You can hear your training now.', + outcome: 'level8_complete' + } + } + } + }, + + level9: { + id: 'academy-level-9', + name: 'Sensory Array', + arc: 'Feature Discovery', + level: 9, + duration: 3600, // 60 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 9: Sensory Array', + steps: { + start: { + type: 'story', + mood: 'overwhelming', + story: 'Two videos was intense. But you are ready for more. QUAD VIDEO MODE: Four simultaneous porn streams. Your screen will be filled with bodies, moaning, fucking. Everywhere you look - porn. This is the gooner\'s paradise.', + nextStep: 'quad_video_start' + }, + quad_video_start: { + type: 'action', + mood: 'extreme', + story: 'Activating quad video array. FOUR screens. Top left. Top right. Bottom left. Bottom right. All porn. All at once. Let it wash over you. Let it consume you.', + interactiveType: 'quad-video', + params: { layout: 'grid', videos: ['random', 'random', 'random', 'random'] }, + nextStep: 'quad_edges' + }, + quad_edges: { + type: 'action', + mood: 'relentless', + story: 'Edge 40 times. While all four videos play. Your brain cannot process it all. That\'s fine. Let it become noise. Let it become background. Let it become EVERYTHING. This is full sensory immersion.', + interactiveType: 'edge', + params: { count: 40, instruction: 'Edge 40 times to quad video array' }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'overwhelming', + story: '✅ Level 9 Complete - QUAD VIDEO UNLOCKED. Four screens. Infinite pleasure.', + outcome: 'level9_complete' + } + } + } + }, + + level10: { + id: 'academy-level-10', + name: 'Hypnotic Gateway', + arc: 'Feature Discovery', + level: 10, + isCheckpoint: true, + duration: 4200, // 70 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 10: Hypnotic Gateway - Checkpoint', + steps: { + start: { + type: 'story', + mood: 'trance-like', + story: 'You have unlocked webcam, dual video, TTS, and quad video. Now we add the final piece of Feature Discovery: the hypno spiral. Stare into it. Let it pull you deeper. This is your second checkpoint. You are halfway to mastery.', + nextStep: 'preference_checkpoint' + }, + preference_checkpoint: { + type: 'action', + mood: 'reflective', + story: 'Before the spiral, update your preferences again. What have you discovered about yourself in levels 6-9? What turns you on most now? Configure yourself.', + interactiveType: 'update-preferences', + params: { checkpoint: 10 }, + nextStep: 'hypno_spiral_start' + }, + hypno_spiral_start: { + type: 'action', + mood: 'hypnotic', + story: 'Now... the spiral. Stare at the center. Watch it spin. Round and round. Deeper and deeper. Your mind empties. Only gooning remains. Only edging. Only porn.', + interactiveType: 'hypno-spiral', + params: { duration: 120, overlay: true, opacity: 0.5 }, + nextStep: 'trance_edges' + }, + trance_edges: { + type: 'action', + mood: 'deep', + story: 'While in trance, edge 50 times. Let the spiral guide you. Let it program you. You are becoming what you were meant to be.', + interactiveType: 'edge', + params: { count: 50, instruction: 'Edge 50 times under the spiral\'s influence' }, + nextStep: 'arc_complete' + }, + arc_complete: { + type: 'story', + mood: 'accomplished', + story: 'Feature Discovery Arc Complete. You have unlocked all basic features: webcam, dual/quad video, TTS, hypno spiral. Arc 3 awaits: Mind & Body. The real transformation begins.', + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'transformative', + story: '✅🎯 Level 10 Complete - FEATURE DISCOVERY ARC FINISHED. All features unlocked. Mind & Body training next.', + outcome: 'level10_complete' + } + } + } + }, + + // MIND & BODY ARC (Levels 11-15) + level11: { + id: 'academy-level-11', + name: 'Mind Sync', + arc: 'Mind & Body', + level: 11, + duration: 4500, // 75 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 11: Mind Sync', + steps: { + start: { + type: 'story', + mood: 'mysterious', + story: 'Welcome to Arc 3: Mind & Body. You\'ve mastered the tools. Now we go deeper. The spiral... the words... they will merge. Your mind and body will sync in ways you haven\'t experienced. This is where transformation accelerates.', + nextStep: 'hypno_intro' + }, + hypno_intro: { + type: 'action', + mood: 'hypnotic', + story: 'First, the spiral. Watch it spin. But this time, words will appear. Read them. Let them sink in. The combination rewires you faster than either alone.', + interactiveType: 'hypno-caption-combo', + params: { + hypnoDuration: 180, + captions: [ + { text: 'You are a dedicated gooner', delay: 10 }, + { text: 'Edging is your purpose', delay: 40 }, + { text: 'The spiral guides you', delay: 70 }, + { text: 'Deeper into pleasure', delay: 100 }, + { text: 'You belong here', delay: 130 }, + { text: 'Gooning is freedom', delay: 160 } + ] + }, + nextStep: 'edge_session' + }, + edge_session: { + type: 'action', + mood: 'intense', + story: 'Good. Your mind is more receptive now. Edge 30 times while the quad video plays. Let the spiral\'s lessons guide your stroking.', + interactiveType: 'free-edge-session', + params: { + duration: 2700, + targetEdges: 30, + features: ['quad-video'] + }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'accomplished', + story: '✅ Level 11 Complete - Mind and body are beginning to sync. The words take root.', + outcome: 'level11_complete' + } + } + } + }, + + level12: { + id: 'academy-level-12', + name: 'Caption Conditioning', + arc: 'Mind & Body', + level: 12, + duration: 4800, // 80 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 12: Caption Conditioning', + steps: { + start: { + type: 'story', + mood: 'focused', + story: 'Today, the captions become personal. Based on what you\'ve told me about your preferences, I will show you words tailored to YOUR desires. They will feel... familiar. Comfortable. True.', + nextStep: 'dynamic_captions' + }, + dynamic_captions: { + type: 'action', + mood: 'personalized', + story: 'Watch the videos. Read the words. They know you. They speak to what you crave. Edge 35 times as they condition you.', + interactiveType: 'dynamic-captions', + params: { + duration: 3000, + captionSource: 'preference-based', + frequency: 15, + edgeCount: 35, + features: ['dual-video'] + }, + nextStep: 'reflection' + }, + reflection: { + type: 'story', + mood: 'affirming', + story: 'You felt it, didn\'t you? How the words resonated. That\'s because they\'re YOUR truth. The Academy knows you now. Knows what you need.', + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'satisfied', + story: '✅ Level 12 Complete - Your mind accepts its conditioning willingly.', + outcome: 'level12_complete' + } + } + } + }, + + level13: { + id: 'academy-level-13', + name: 'Voice in the Spiral', + arc: 'Mind & Body', + level: 13, + duration: 5100, // 85 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 13: Voice in the Spiral', + steps: { + start: { + type: 'story', + mood: 'commanding', + story: 'Now we combine it all. My voice. The spiral. Together they will guide you deeper than ever before. Listen. Watch. Obey.', + nextStep: 'tts_hypno' + }, + tts_hypno: { + type: 'action', + mood: 'trance', + story: 'The spiral spins. My voice speaks. You follow both without question.', + interactiveType: 'tts-hypno-sync', + params: { + spiralDuration: 300, + ttsCommands: [ + { text: 'Watch the spiral... let it pull you in', delay: 10 }, + { text: 'Your hand moves on its own now', delay: 60 }, + { text: 'Deeper... always deeper', delay: 120 }, + { text: 'You are becoming what you were meant to be', delay: 180 }, + { text: 'A perfect gooner', delay: 240 } + ] + }, + nextStep: 'edge_in_trance' + }, + edge_in_trance: { + type: 'action', + mood: 'entranced', + story: 'Now edge 40 times while remaining in this state. My voice will guide you. The videos will fuel you.', + interactiveType: 'free-edge-session', + params: { + duration: 3600, + targetEdges: 40, + features: ['quad-video', 'tts'] + }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'deep', + story: '✅ Level 13 Complete - Voice and spiral merge in your mind.', + outcome: 'level13_complete' + } + } + } + }, + + level14: { + id: 'academy-level-14', + name: 'Sensory Overload', + arc: 'Mind & Body', + level: 14, + duration: 5400, // 90 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 14: Sensory Overload', + steps: { + start: { + type: 'story', + mood: 'intense', + story: 'Everything. All at once. Four videos. The spiral. My voice. Captions. This is total immersion. This is where weak minds break... and dedicated gooners thrive. Are you ready?', + nextStep: 'overload_begins' + }, + overload_begins: { + type: 'action', + mood: 'overwhelming', + story: 'ALL FEATURES ACTIVE. Quad video. Hypno spiral overlay. TTS commands. Dynamic captions. Edge 45 times in this sensory storm.', + interactiveType: 'sensory-overload', + params: { + features: ['quad-video', 'hypno', 'tts', 'captions'], + duration: 4200, + edgeCount: 45 + }, + nextStep: 'survived' + }, + survived: { + type: 'story', + mood: 'triumphant', + story: 'You survived. No... you THRIVED. Your mind didn\'t break under the overload. It adapted. Embraced it. You\'re ready for the checkpoint.', + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'powerful', + story: '✅ Level 14 Complete - Sensory overload is your new normal.', + outcome: 'level14_complete' + } + } + } + }, + + level15: { + id: 'academy-level-15', + name: 'Mind & Body Checkpoint', + arc: 'Mind & Body', + level: 15, + duration: 6000, // 100 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 15: Mind & Body Checkpoint', + steps: { + start: { + type: 'story', + mood: 'reflective', + story: '🎯 CHECKPOINT - Mind & Body Arc Complete. You\'ve learned to sync mind and body through hypno, captions, and voice. Before advancing to Advanced Training, we update your preferences based on your progress.', + nextStep: 'preferences' + }, + preferences: { + type: 'action', + mood: 'administrative', + story: 'Update your preferences to reflect your evolution. Your tastes may have... expanded.', + interactiveType: 'update-preferences', + params: { + checkpoint: 'mind-body', + level: 15 + }, + nextStep: 'final_session' + }, + final_session: { + type: 'action', + mood: 'celebratory', + story: 'One final free session with all Mind & Body features to cement your training. Edge 50 times. Show me everything you\'ve learned.', + interactiveType: 'free-edge-session', + params: { + duration: 4200, + targetEdges: 50, + features: ['quad-video', 'hypno', 'tts', 'captions'] + }, + nextStep: 'arc_complete' + }, + arc_complete: { + type: 'story', + mood: 'accomplished', + story: 'Mind & Body Arc Complete. Your transformation is accelerating. Arc 4 awaits: Advanced Training. Prepare for interruptions, denial, and total control.', + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'transformative', + story: '✅🎯 Level 15 Complete - MIND & BODY ARC FINISHED. Advanced Training begins.', + outcome: 'level15_complete' + } + } + } + }, + + // ADVANCED TRAINING ARC (Levels 16-20) + level16: { + id: 'academy-level-16', + name: 'Controlled Chaos', + arc: 'Advanced Training', + level: 16, + duration: 6600, // 110 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 16: Controlled Chaos', + steps: { + start: { + type: 'story', + mood: 'ominous', + story: 'Welcome to Advanced Training. You will not always be in control anymore. I will interrupt you. Randomly. Without warning. You will obey these interruptions instantly. This teaches true submission.', + nextStep: 'enable_interruptions' + }, + enable_interruptions: { + type: 'action', + mood: 'commanding', + story: 'Interruptions are now ACTIVE. They will come when you least expect them. Edge, pose, stop, repeat mantras... you will comply immediately.', + interactiveType: 'enable-interruptions', + params: { + types: ['edge', 'pose', 'mantra', 'stop-stroking'], + frequency: 'medium', + randomize: true + }, + nextStep: 'chaotic_session' + }, + chaotic_session: { + type: 'action', + mood: 'unpredictable', + story: 'Begin your edging session. 50 edges. But remember... interruptions will come. Obey them without hesitation.', + interactiveType: 'free-edge-session', + params: { + duration: 5400, + targetEdges: 50, + features: ['quad-video', 'interruptions'] + }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'controlled', + story: '✅ Level 16 Complete - You respond to chaos with obedience.', + outcome: 'level16_complete' + } + } + } + }, + + level17: { + id: 'academy-level-17', + name: 'The Denial Dance', + arc: 'Advanced Training', + level: 17, + duration: 7200, // 120 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 17: The Denial Dance', + steps: { + start: { + type: 'story', + mood: 'cruel', + story: 'Denial. The ultimate test of a gooner\'s discipline. Today, you will stroke... and stop. Stroke... and stop. Over and over. Building frustration. Building need. You will NOT cum.', + nextStep: 'denial_intro' + }, + denial_intro: { + type: 'action', + mood: 'teasing', + story: 'Denial training begins. Periods of stroking, then forced stops. Your body will beg for release. Your mind will stay strong.', + interactiveType: 'denial-training', + params: { + denialPeriods: [ + { allowStroking: 300, instruction: 'Stroke freely for 5 minutes' }, + { stopDuration: 120, instruction: 'HANDS OFF. No touching for 2 minutes' }, + { allowStroking: 420, instruction: 'Stroke again for 7 minutes' }, + { stopDuration: 180, instruction: 'STOP. 3 minutes of pure denial' }, + { allowStroking: 600, instruction: 'Final stroking period: 10 minutes' }, + { stopDuration: 240, instruction: 'FINAL DENIAL. 4 minutes. No release.' } + ] + }, + nextStep: 'edge_denied' + }, + edge_denied: { + type: 'action', + mood: 'frustrated', + story: 'Now edge 55 times while denied. Feel that tension. That ache. That\'s discipline.', + interactiveType: 'free-edge-session', + params: { + duration: 3600, + targetEdges: 55, + features: ['quad-video', 'denial'] + }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'denied', + story: '✅ Level 17 Complete - Denial builds stronger gooners.', + outcome: 'level17_complete' + } + } + } + }, + + level18: { + id: 'academy-level-18', + name: 'Popup Distraction', + arc: 'Advanced Training', + level: 18, + duration: 7800, // 130 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 18: Popup Distraction', + steps: { + start: { + type: 'story', + mood: 'playful', + story: 'Popups. Random images will appear over your videos. Tasks. Consequences. Poses. You must acknowledge them while maintaining your gooning. Divided attention is advanced skill.', + nextStep: 'enable_popups' + }, + enable_popups: { + type: 'action', + mood: 'distracting', + story: 'Popup system ACTIVE. Images will appear randomly. Read them. Obey them if they command. Continue gooning regardless.', + interactiveType: 'enable-popups', + params: { + frequency: 'medium', + sources: ['tasks', 'consequences'], + duration: 10, + randomize: true + }, + nextStep: 'popup_session' + }, + popup_session: { + type: 'action', + mood: 'multitasking', + story: 'Edge 60 times while popups distract you. Maintain focus on BOTH the videos AND the popups.', + interactiveType: 'free-edge-session', + params: { + duration: 6600, + targetEdges: 60, + features: ['quad-video', 'popups', 'interruptions'] + }, + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'distracted', + story: '✅ Level 18 Complete - Distractions enhance, not hinder, your gooning.', + outcome: 'level18_complete' + } + } + } + }, + + level19: { + id: 'academy-level-19', + name: 'Total Immersion', + arc: 'Advanced Training', + level: 19, + duration: 8400, // 140 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 19: Total Immersion', + steps: { + start: { + type: 'story', + mood: 'ultimate', + story: 'Everything. Every feature. Every skill. All at once. This is total immersion. Quad video, hypno, TTS, captions, interruptions, denial, popups. If you can goon through THIS, you\'re ready for Level 20.', + nextStep: 'total_immersion' + }, + total_immersion: { + type: 'action', + mood: 'overwhelming', + story: 'ALL SYSTEMS ACTIVE. Every feature unlocked. Every distraction enabled. Edge 70 times in this chaos. Prove your mastery.', + interactiveType: 'sensory-overload', + params: { + features: ['quad-video', 'hypno', 'tts', 'captions', 'interruptions', 'popups'], + duration: 7200, + edgeCount: 70 + }, + nextStep: 'mastery_achieved' + }, + mastery_achieved: { + type: 'story', + mood: 'victorious', + story: 'Unbelievable. You didn\'t just survive. You MASTERED it. Total immersion. Every feature. You\'re ready for the final checkpoint.', + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'masterful', + story: '✅ Level 19 Complete - Total immersion is your element.', + outcome: 'level19_complete' + } + } + } + }, + + level20: { + id: 'academy-level-20', + name: 'Ultimate Checkpoint', + arc: 'Advanced Training', + level: 20, + duration: 9000, // 150 minutes + interactiveType: 'scenario-adventure', + interactiveData: { + title: 'Level 20: Ultimate Checkpoint', + steps: { + start: { + type: 'story', + mood: 'ceremonial', + story: '🎯 ULTIMATE CHECKPOINT - Advanced Training Arc Complete. Levels 1-20 finished. You have unlocked every feature, mastered every skill. Before the final arcs, we update your preferences one more time.', + nextStep: 'preferences' + }, + preferences: { + type: 'action', + mood: 'administrative', + story: 'Final preference update for Levels 1-20. Your journey has been profound. Document your evolution.', + interactiveType: 'update-preferences', + params: { + checkpoint: 'advanced-training', + level: 20 + }, + nextStep: 'ultimate_session' + }, + ultimate_session: { + type: 'action', + mood: 'epic', + story: 'The ultimate session. 90 minutes. ALL features. Edge 80 times. This is your masterpiece. Show me EVERYTHING.', + interactiveType: 'free-edge-session', + params: { + duration: 5400, + targetEdges: 80, + features: ['quad-video', 'hypno', 'tts', 'captions', 'interruptions', 'popups', 'webcam'] + }, + nextStep: 'arc_complete' + }, + arc_complete: { + type: 'story', + mood: 'triumphant', + story: 'Advanced Training Arc Complete. Levels 1-20: DONE. You are no longer a student. You are a master gooner. Path Specialization awaits.', + nextStep: 'completion' + }, + completion: { + type: 'completion', + mood: 'legendary', + story: '✅🎯🏆 Level 20 Complete - ADVANCED TRAINING ARC FINISHED. First 20 levels mastered. Specialization next.', + outcome: 'level20_complete' + } + } + } + } + }, + // Configuration for gooner training mode config: { progressionSystem: { diff --git a/src/data/poseBanks/inventoryPoseBank.js b/src/data/poseBanks/inventoryPoseBank.js new file mode 100644 index 0000000..732cd70 --- /dev/null +++ b/src/data/poseBanks/inventoryPoseBank.js @@ -0,0 +1,250 @@ +/** + * Inventory-Based Pose Bank + * Poses organized by item type and intensity + */ + +const inventoryPoseBank = { + // Basic poses (no items required) + basic: [ + { + name: "Standing Neutral", + instruction: "Stand naturally with hands at sides", + description: "Basic standing position for documentation" + }, + { + name: "Kneeling Submission", + instruction: "Kneel with hands on thighs, head slightly bowed", + description: "Submissive kneeling position" + }, + { + name: "Sitting Display", + instruction: "Sit with legs together, hands in lap", + description: "Modest sitting position" + } + ], + + // Panty-specific poses + panty: [ + { + name: "Panty Display", + instruction: "Standing, pull waistband to show panties clearly", + description: "Display your panties for the camera" + }, + { + name: "Panty Peek", + instruction: "Bent over, looking back at camera to show panties", + description: "Bend to reveal your panties" + }, + { + name: "Panties Down", + instruction: "Pull panties down to mid-thigh, exposed", + description: "Lower your panties to expose yourself" + }, + { + name: "Panty Adjustment", + instruction: "Hands adjusting panties, showing waistband", + description: "Adjust your panties for the camera" + } + ], + + // Bra-specific poses + bra: [ + { + name: "Bra Display", + instruction: "Arms behind back, chest forward to display bra", + description: "Show off your bra" + }, + { + name: "Bra Adjustment", + instruction: "Hands adjusting bra straps or cups", + description: "Adjust your bra for proper fit" + }, + { + name: "Strap Show", + instruction: "Pull strap to show bra clearly", + description: "Display your bra strap" + } + ], + + // Dress/Skirt poses + dress: [ + { + name: "Twirl Display", + instruction: "Spin in circle, dress/skirt fanning out", + description: "Twirl to show off your outfit" + }, + { + name: "Dress Lift", + instruction: "Lift hem to show what's underneath", + description: "Lift your dress to reveal beneath" + }, + { + name: "Sitting Ladylike", + instruction: "Sit with legs crossed, smoothing dress", + description: "Sit properly in your feminine outfit" + }, + { + name: "Curtsy", + instruction: "Hold dress edges, cross leg behind, bow head", + description: "Perform a proper feminine curtsy" + }, + { + name: "Dress Adjust", + instruction: "Standing, adjust dress while posing", + description: "Adjust your dress demurely" + } + ], + + // Heel-specific poses + heel: [ + { + name: "Heel Display Standing", + instruction: "Standing with one foot forward to show heels", + description: "Display your heels while standing" + }, + { + name: "Walking Pose", + instruction: "Mid-step pose showing heel and posture", + description: "Pose as if walking in heels" + }, + { + name: "Kneeling in Heels", + instruction: "Kneel while keeping heels on", + description: "Kneel without removing your heels" + }, + { + name: "Bent Over in Heels", + instruction: "Bend at waist while wearing heels", + description: "Bend over while in heels" + } + ], + + // Toy poses + toy: [ + { + name: "Dildo to Mouth", + instruction: "Hold dildo near or touching mouth", + description: "Display toy near your mouth" + }, + { + name: "Plug Display", + instruction: "Bent over to show inserted plug", + description: "Reveal your inserted plug" + }, + { + name: "Chastity Show", + instruction: "Standing or sitting, display locked cage/belt", + description: "Show your chastity device" + }, + { + name: "Restrained Position", + instruction: "Pose with wrists/ankles in restraints", + description: "Display yourself in restraints" + }, + { + name: "Gagged Display", + instruction: "Head up, show gag clearly", + description: "Display your gag" + }, + { + name: "Clamped Nipples", + instruction: "Chest forward to display nipple clamps", + description: "Show your clamped nipples" + }, + { + name: "Toy Insertion Pose", + instruction: "Positioned to show toy insertion", + description: "Pose showing toy being used" + } + ], + + // Edging poses + edging: [ + { + name: "Standing Edge", + instruction: "Standing while edging yourself", + description: "Edge while standing upright" + }, + { + name: "Kneeling Edge", + instruction: "Kneeling while edging, maintain posture", + description: "Edge while in kneeling position" + }, + { + name: "Bent Over Edge", + instruction: "Bent over while edging yourself", + description: "Edge while bent at the waist" + }, + { + name: "Spread Eagle Edge", + instruction: "Lying back, legs spread, edging", + description: "Edge while fully spread" + }, + { + name: "Squatting Edge", + instruction: "Deep squat while edging, legs wide", + description: "Edge in degrading squat position" + }, + { + name: "Mirror Edge", + instruction: "Edge while watching yourself in mirror", + description: "Edge while seeing your reflection" + }, + { + name: "Thigh Squeeze Edge", + instruction: "Sitting or lying, squeeze thighs to edge", + description: "Edge by squeezing thighs together" + }, + { + name: "On Back Edge", + instruction: "Lying on back with legs spread, edge yourself", + description: "Edge while on your back" + }, + { + name: "Dressed Edge", + instruction: "Edge while fully dressed in feminine outfit", + description: "Edge while wearing your outfit" + }, + { + name: "Exposed Edge", + instruction: "Standing against wall, spread, edge while exposed", + description: "Edge while fully exposed" + } + ] +}; + +/** + * Select pose based on category + */ +function selectPoseForCategory(category, usedPoses = new Set()) { + const poses = inventoryPoseBank[category] || inventoryPoseBank.basic; + + // Filter out used poses + const availablePoses = poses.filter(pose => !usedPoses.has(pose.name)); + + // If all poses used, reset + if (availablePoses.length === 0) { + console.log(`🔄 All ${category} poses used - resetting`); + return selectPoseForCategory(category, new Set()); + } + + // Select random pose + const randomIndex = Math.floor(Math.random() * availablePoses.length); + const selectedPose = availablePoses[randomIndex]; + + console.log(`📸 Selected ${category} pose: ${selectedPose.name}`); + + return selectedPose; +} + +/** + * Get all poses for a category + */ +function getPosesByCategory(category) { + return inventoryPoseBank[category] || inventoryPoseBank.basic; +} + +// Make available globally +window.inventoryPoseBank = inventoryPoseBank; +window.selectPoseForCategory = selectPoseForCategory; +window.getPosesByCategory = getPosesByCategory; diff --git a/src/features/academy/academyLevelData.js b/src/features/academy/academyLevelData.js new file mode 100644 index 0000000..fe787c4 --- /dev/null +++ b/src/features/academy/academyLevelData.js @@ -0,0 +1,2426 @@ +/** + * Academy Level Data Configuration + * Defines detailed configurations for all 30 training levels + * Phase 2: Level Data & Content Configuration + */ + +class AcademyLevelData { + constructor() { + this.levels = this.initializeLevelConfigs(); + } + + /** + * Get configuration for a specific level + * @param {number} levelNumber - Level number (1-30) + * @returns {Object} Level configuration + */ + getLevelConfig(levelNumber) { + return this.levels[levelNumber] || null; + } + + /** + * Get all levels for a specific arc + * @param {number} arcNumber - Arc number (1-6) + * @returns {Array} Array of level configs + */ + getArcLevels(arcNumber) { + return Object.values(this.levels).filter(level => level.arc === arcNumber); + } + + /** + * Initialize all 30 level configurations + * @returns {Object} Map of level numbers to configurations + */ + initializeLevelConfigs() { + const manualLevels = { + // ARC 1: AWAKENING (Levels 1-5) + 1: { + levelNumber: 1, + arc: 1, + arcName: "Awakening", + title: "Introduction", + subtitle: "Your Journey Begins", + description: "Welcome to The Academy. Begin your training with simple focus exercises and learn the fundamentals of edging and control.", + + // Session configuration + session: { + duration: { min: 10, target: 15, max: 20 }, // minutes + tasks: { + total: 3, + types: ['edge', 'focus', 'obey'], + difficulty: 'beginner' + }, + breaks: { + enabled: true, + frequency: 5, // every 5 minutes + duration: 30 // seconds + } + }, + + // Media requirements + media: { + videos: { + required: 2, + categories: ['solo', 'soft', 'pov'], + duration: { min: 5, max: 15 }, + preferenceWeight: 0.3 // 30% user preference, 70% level requirements + }, + images: { + required: 3, + categories: ['soft', 'artistic'], + timing: 'task-completion' + } + }, + + // Task definitions + tasks: [ + { + type: 'edge', + count: 3, + duration: 120, // seconds per edge + intensity: 'gentle', + instructions: "Edge slowly and steadily. Focus on the sensations. Stop before the point of no return.", + successCriteria: { + edges: 3, + cooldown: 30 // seconds between edges + } + }, + { + type: 'focus', + duration: 180, + target: 'video', + instructions: "Watch and focus. Let the content guide your arousal. No touching yet.", + distractions: 'minimal' + }, + { + type: 'obey', + commands: ['stroke', 'stop', 'slow'], + timing: 'audio-cue', + instructions: "Follow the commands exactly as given. Build your obedience." + } + ], + + // Objectives and rewards + objectives: [ + "Complete 3 edges without going over", + "Maintain focus for the full session", + "Follow all commands without hesitation" + ], + + rewards: { + xp: 100, + unlocks: ['Level 2'], + achievements: ['First Steps'] + }, + + // Story/narrative elements + story: { + intro: "Welcome, trainee. Today marks the beginning of your transformation. We'll start simple - learning control, building focus, understanding your limits.", + checkpoint: null, + outro: "Well done. You've completed your first session. This is just the beginning of your journey." + }, + + // Completion criteria + completion: { + required: { + tasksCompleted: 3, + edgesAchieved: 3, + timeSpent: 10 // minimum minutes + }, + optional: { + perfectEdges: 3, // bonus for all edges being perfect + noMistakes: true + } + } + }, + + 2: { + levelNumber: 2, + arc: 1, + arcName: "Awakening", + title: "First Steps", + subtitle: "Building the Foundation", + description: "Now that you understand the basics, we'll increase the intensity slightly. More edges, longer focus periods.", + + session: { + duration: { min: 15, target: 20, max: 25 }, + tasks: { + total: 4, + types: ['edge', 'focus', 'endurance', 'obey'], + difficulty: 'beginner' + }, + breaks: { + enabled: true, + frequency: 7, + duration: 30 + } + }, + + media: { + videos: { + required: 3, + categories: ['solo', 'couples', 'soft', 'moderate'], + duration: { min: 5, max: 20 }, + preferenceWeight: 0.4 + }, + images: { + required: 5, + categories: ['soft', 'moderate'], + timing: 'between-tasks' + } + }, + + tasks: [ + { + type: 'edge', + count: 5, + duration: 120, + intensity: 'moderate', + instructions: "Five edges today. Take your time. Feel the build-up each time.", + successCriteria: { + edges: 5, + cooldown: 45 + } + }, + { + type: 'focus', + duration: 240, + target: 'video', + instructions: "Extended focus session. Watch without touching. Build anticipation.", + distractions: 'low' + }, + { + type: 'endurance', + duration: 180, + stroking: { + pace: 'slow', + pattern: 'steady', + breaks: 'as-needed' + }, + instructions: "Stroke slowly for 3 minutes. Maintain arousal but stay in control." + }, + { + type: 'obey', + commands: ['stroke', 'stop', 'slow', 'fast', 'edge'], + timing: 'visual-audio-cue', + instructions: "More varied commands today. Stay responsive and obedient." + } + ], + + objectives: [ + "Complete 5 edges with control", + "Endure the full focus period", + "Respond to all commands immediately" + ], + + rewards: { + xp: 150, + unlocks: ['Level 3'], + achievements: [] + }, + + story: { + intro: "You're progressing well. Today we build on yesterday's foundation. More edges, longer sessions, better control.", + checkpoint: null, + outro: "Excellent work. You're learning to control your arousal. This discipline will serve you well." + }, + + completion: { + required: { + tasksCompleted: 4, + edgesAchieved: 5, + timeSpent: 15 + }, + optional: { + perfectEdges: 5, + noBreaks: true + } + } + }, + + 3: { + levelNumber: 3, + arc: 1, + arcName: "Awakening", + title: "Building Endurance", + subtitle: "Longer, Stronger", + description: "Test your stamina with extended edging sessions and longer stroke periods. Your endurance must grow.", + + session: { + duration: { min: 20, target: 25, max: 30 }, + tasks: { + total: 5, + types: ['edge', 'endurance', 'focus', 'pattern', 'obey'], + difficulty: 'beginner-intermediate' + }, + breaks: { + enabled: true, + frequency: 8, + duration: 30 + } + }, + + media: { + videos: { + required: 4, + categories: ['solo', 'couples', 'moderate', 'pov'], + duration: { min: 10, max: 25 }, + preferenceWeight: 0.5 + }, + images: { + required: 6, + categories: ['moderate', 'artistic'], + timing: 'task-transition' + } + }, + + tasks: [ + { + type: 'edge', + count: 7, + duration: 150, + intensity: 'moderate', + instructions: "Seven edges. Longer build-up. Really feel each one approaching.", + successCriteria: { + edges: 7, + cooldown: 60 + } + }, + { + type: 'endurance', + duration: 300, + stroking: { + pace: 'moderate', + pattern: 'steady', + breaks: 'minimal' + }, + instructions: "Five minutes of steady stroking. Build your stamina. Control your arousal." + }, + { + type: 'focus', + duration: 180, + target: 'multiple-videos', + instructions: "Watch multiple videos. Switch between them. Maintain arousal.", + distractions: 'moderate' + }, + { + type: 'pattern', + duration: 240, + pattern: { + sequence: [10, 20, 10, 30, 10, 20], + unit: 'strokes', + rest: 10 + }, + instructions: "Follow the stroke pattern: 10 fast, 20 slow, 10 fast, 30 slow, repeat." + }, + { + type: 'obey', + commands: ['stroke', 'stop', 'slow', 'fast', 'edge', 'hold'], + timing: 'random-intervals', + instructions: "Commands will come at random. Stay alert and ready to obey." + } + ], + + objectives: [ + "Complete 7 edges maintaining control", + "Endure 5+ minutes of continuous stroking", + "Follow complex stroke patterns accurately" + ], + + rewards: { + xp: 200, + unlocks: ['Level 4'], + achievements: ['Endurance Builder'] + }, + + story: { + intro: "Your control is improving. Now we test your endurance. Longer sessions, more edges, complex patterns.", + checkpoint: null, + outro: "Impressive stamina. You're learning to sustain arousal over longer periods without losing control." + }, + + completion: { + required: { + tasksCompleted: 5, + edgesAchieved: 7, + timeSpent: 20 + }, + optional: { + perfectEdges: 7, + patternAccuracy: 0.9 + } + } + }, + + 4: { + levelNumber: 4, + arc: 1, + arcName: "Awakening", + title: "Deeper Focus", + subtitle: "Mind Over Matter", + description: "Mental discipline is as important as physical control. Extended focus exercises while maintaining arousal.", + + session: { + duration: { min: 25, target: 30, max: 35 }, + tasks: { + total: 5, + types: ['focus', 'edge', 'denial', 'pattern', 'obey'], + difficulty: 'intermediate' + }, + breaks: { + enabled: true, + frequency: 10, + duration: 45 + } + }, + + media: { + videos: { + required: 5, + categories: ['moderate', 'intense', 'pov', 'compilation'], + duration: { min: 10, max: 30 }, + preferenceWeight: 0.6 + }, + images: { + required: 8, + categories: ['moderate', 'intense', 'artistic'], + timing: 'focus-periods' + } + }, + + tasks: [ + { + type: 'focus', + duration: 360, + target: 'intense-content', + instructions: "Six minutes of pure focus. Intense content. No touching. Only watching.", + distractions: 'high', + arousal: 'maintain-high' + }, + { + type: 'edge', + count: 8, + duration: 180, + intensity: 'intense', + instructions: "Eight edges today. Quick succession. Test your control limits.", + successCriteria: { + edges: 8, + cooldown: 45 + } + }, + { + type: 'denial', + duration: 180, + stroking: 'allowed', + edging: 'forbidden', + instructions: "Stroke but don't edge. Stay below that threshold. Practice restraint." + }, + { + type: 'pattern', + duration: 300, + pattern: { + sequence: [30, 10, 20, 10, 40, 10], + unit: 'seconds', + strokeType: ['slow', 'fast', 'medium', 'fast', 'slow', 'fast'], + rest: 15 + }, + instructions: "Complex timed pattern. Different speeds. Maintain rhythm." + }, + { + type: 'obey', + commands: ['stroke', 'stop', 'edge', 'deny', 'focus', 'breathe'], + timing: 'audio-visual-sync', + instructions: "Commands synchronized with media. Perfect timing required." + } + ], + + objectives: [ + "Maintain focus for 6+ minutes without touching", + "Complete 8 edges in quick succession", + "Practice denial - stroke without edging" + ], + + rewards: { + xp: 250, + unlocks: ['Level 5'], + achievements: ['Mind Master'] + }, + + story: { + intro: "Mental discipline separates the novice from the dedicated. Today we train your mind as much as your body.", + checkpoint: null, + outro: "Your focus is sharpening. Mind and body are learning to work together in harmony." + }, + + completion: { + required: { + tasksCompleted: 5, + edgesAchieved: 8, + focusTime: 6, + timeSpent: 25 + }, + optional: { + perfectFocus: true, + denialSuccess: true + } + } + }, + + 5: { + levelNumber: 5, + arc: 1, + arcName: "Awakening", + title: "Checkpoint: First Assessment", + subtitle: "Prove Your Progress", + description: "Your first major checkpoint. A comprehensive test of everything learned so far. Update your preferences and review your progress.", + + session: { + duration: { min: 30, target: 40, max: 50 }, + tasks: { + total: 7, + types: ['edge', 'endurance', 'focus', 'pattern', 'denial', 'obey', 'challenge'], + difficulty: 'intermediate' + }, + breaks: { + enabled: true, + frequency: 12, + duration: 60 + } + }, + + media: { + videos: { + required: 6, + categories: 'user-preferences', // Fully respect user preferences at checkpoints + duration: { min: 10, max: 40 }, + preferenceWeight: 1.0 // 100% user preference + }, + images: { + required: 10, + categories: 'user-preferences', + timing: 'throughout' + } + }, + + tasks: [ + { + type: 'edge', + count: 10, + duration: 180, + intensity: 'varied', + instructions: "Ten edges. Your control will be tested. Vary the intensity.", + successCriteria: { + edges: 10, + cooldown: 60, + varietyRequired: true + } + }, + { + type: 'endurance', + duration: 420, + stroking: { + pace: 'varied', + pattern: 'complex', + breaks: 'strategic' + }, + instructions: "Seven minutes continuous. Vary your pace. Manage your arousal strategically." + }, + { + type: 'focus', + duration: 300, + target: 'preferred-content', + instructions: "Pure focus on your favorite content. No touching. High arousal maintenance.", + distractions: 'high', + arousal: 'critical' + }, + { + type: 'pattern', + duration: 360, + pattern: { + sequence: 'adaptive', // Adjusts to performance + complexity: 'high' + }, + instructions: "Advanced patterns that adapt to your performance. Stay focused." + }, + { + type: 'denial', + duration: 240, + stroking: 'required', + edging: 'forbidden', + challenge: 'intense-content', + instructions: "Ultimate denial test. Intense content. Stroke but never edge. Show your discipline." + }, + { + type: 'obey', + commands: 'full-set', + timing: 'complex', + instructions: "All command types. Complex timing. Perfect obedience expected." + }, + { + type: 'challenge', + description: 'checkpoint-assessment', + requirements: { + combinedEdges: 10, + combinedFocus: 5, + combinedEndurance: 7, + perfectObedience: true + }, + instructions: "Final challenge: Combine everything you've learned. Edge, focus, endure, obey." + } + ], + + objectives: [ + "Complete all 7 task types successfully", + "Achieve 10 perfect edges", + "Demonstrate mastery of Arc 1 skills" + ], + + rewards: { + xp: 500, + unlocks: ['Level 6', 'Arc 2: Exploration'], + achievements: ['Arc 1 Complete', 'Foundation Master'], + bonuses: { + preferenceUpdate: true, + libraryAccess: 'expanded' + } + }, + + story: { + intro: "This is your first checkpoint. A comprehensive assessment of your progress through Arc 1. Show me everything you've learned.", + checkpoint: { + preferenceModal: true, + progressSummary: true, + statsDisplay: true + }, + outro: "Outstanding. You've completed Arc 1: Awakening. You've built the foundation - control, endurance, focus, obedience. Arc 2 awaits." + }, + + completion: { + required: { + tasksCompleted: 7, + edgesAchieved: 10, + focusTime: 5, + enduranceTime: 7, + timeSpent: 30 + }, + optional: { + perfectScore: true, + allBonusesEarned: true + } + } + }, + + // ARC 2: EXPLORATION (Levels 6-10) + 6: { + levelNumber: 6, + arc: 2, + arcName: "Exploration", + title: "New Sensations", + subtitle: "Expanding Your Horizons", + description: "Arc 2 begins. Explore new types of content, new stroking techniques, new ways to build arousal.", + + session: { + duration: { min: 30, target: 35, max: 40 }, + tasks: { + total: 6, + types: ['edge', 'explore', 'pattern', 'focus', 'endurance', 'obey'], + difficulty: 'intermediate' + }, + breaks: { + enabled: true, + frequency: 10, + duration: 45 + } + }, + + media: { + videos: { + required: 6, + categories: ['varied', 'exploration', 'new-experiences'], + duration: { min: 10, max: 30 }, + preferenceWeight: 0.5 + }, + images: { + required: 10, + categories: ['varied', 'artistic', 'intense'], + timing: 'exploration-phase' + } + }, + + tasks: [ + { + type: 'explore', + duration: 300, + content: 'outside-comfort-zone', + instructions: "Try content you don't usually watch. Explore new categories. Open your mind.", + categories: 'suggested-expansion' + }, + { + type: 'edge', + count: 10, + duration: 150, + intensity: 'moderate-intense', + instructions: "Ten edges with new content. See how different stimuli affect you.", + successCriteria: { + edges: 10, + cooldown: 50 + } + }, + { + type: 'pattern', + duration: 300, + pattern: { + sequence: 'exploratory', + variation: 'high', + technique: ['grip-variation', 'speed-changes', 'pressure-control'] + }, + instructions: "Try different techniques. Vary grip, speed, pressure. Find what works." + }, + { + type: 'focus', + duration: 240, + target: 'diverse-content', + instructions: "Rapid content switching. See what captures your attention most.", + distractions: 'moderate' + }, + { + type: 'endurance', + duration: 360, + stroking: { + pace: 'experimental', + pattern: 'varied', + breaks: 'minimal' + }, + instructions: "Six minutes exploring different stroking styles. Find your preferences." + }, + { + type: 'obey', + commands: ['explore', 'switch', 'try-new', 'experiment'], + timing: 'guidance', + instructions: "Commands will guide your exploration. Be open to new experiences." + } + ], + + objectives: [ + "Try at least 3 new content categories", + "Experiment with different stroking techniques", + "Complete 10 edges with varied content" + ], + + rewards: { + xp: 300, + unlocks: ['Level 7'], + achievements: ['Explorer'] + }, + + story: { + intro: "Welcome to Arc 2: Exploration. Now that you have the foundation, it's time to expand. Try new things. Find what truly excites you.", + checkpoint: null, + outro: "Good exploration. You're learning what works for you. This self-knowledge is crucial." + }, + + completion: { + required: { + tasksCompleted: 6, + edgesAchieved: 10, + categoriesExplored: 3, + timeSpent: 30 + }, + optional: { + techniquesDiscovered: 5, + perfectAdaptation: true + } + } + }, + + 7: { + levelNumber: 7, + arc: 2, + arcName: "Exploration", + title: "Variety Training", + subtitle: "Master Multiple Modes", + description: "Learn to switch between different arousal modes. Fast and slow, intense and gentle, visual and mental.", + + session: { + duration: { min: 35, target: 40, max: 45 }, + tasks: { + total: 6, + types: ['edge', 'variety', 'switching', 'focus', 'pattern', 'obey'], + difficulty: 'intermediate' + }, + breaks: { + enabled: true, + frequency: 12, + duration: 60 + } + }, + + media: { + videos: { + required: 8, + categories: ['high-variety', 'contrast-content'], + duration: { min: 5, max: 35 }, + preferenceWeight: 0.6 + }, + images: { + required: 12, + categories: ['varied', 'contrasting'], + timing: 'mode-switches' + } + }, + + tasks: [ + { + type: 'variety', + duration: 420, + modes: ['intense', 'gentle', 'fast', 'slow', 'visual', 'mental'], + switchInterval: 60, + instructions: "Switch between modes every minute. Intense then gentle. Fast then slow. Adapt quickly." + }, + { + type: 'edge', + count: 12, + duration: 120, + intensity: 'varied', + variety: 'required', + instructions: "Twelve edges. Each one different. Vary speed, grip, content, technique.", + successCriteria: { + edges: 12, + cooldown: 40, + varietyRequired: true + } + }, + { + type: 'switching', + duration: 300, + between: ['content-types', 'techniques', 'intensities'], + instructions: "Rapid switching drill. Change content, technique, intensity. Stay aroused through transitions." + }, + { + type: 'focus', + duration: 240, + target: 'contrasting-content', + instructions: "Focus on contrasting content types. Maintain arousal despite variety.", + distractions: 'high' + }, + { + type: 'pattern', + duration: 360, + pattern: { + sequence: 'complex-variety', + modes: ['fast-intense', 'slow-gentle', 'medium-steady'], + transitions: 'smooth' + }, + instructions: "Complex pattern with smooth transitions between different modes." + }, + { + type: 'obey', + commands: ['switch-mode', 'change-speed', 'new-content', 'adapt'], + timing: 'frequent', + instructions: "Frequent mode-switching commands. Adapt quickly and smoothly." + } + ], + + objectives: [ + "Switch between 6 different arousal modes", + "Complete 12 edges with variety", + "Maintain arousal through all transitions" + ], + + rewards: { + xp: 350, + unlocks: ['Level 8'], + achievements: ['Versatile Student'] + }, + + story: { + intro: "Versatility is strength. Today you learn to adapt - switching modes, varying techniques, maintaining arousal through change.", + checkpoint: null, + outro: "Excellent adaptability. You're no longer limited to one mode. This flexibility will serve you well." + }, + + completion: { + required: { + tasksCompleted: 6, + edgesAchieved: 12, + modesSwitched: 6, + timeSpent: 35 + }, + optional: { + smoothTransitions: true, + noArousalDrop: true + } + } + }, + + 8: { + levelNumber: 8, + arc: 2, + arcName: "Exploration", + title: "Extended Sessions", + subtitle: "Building Stamina", + description: "Longer sessions to test your growing stamina. Maintain focus and arousal for extended periods.", + + session: { + duration: { min: 40, target: 50, max: 60 }, + tasks: { + total: 7, + types: ['endurance', 'edge', 'marathon', 'focus', 'pattern', 'denial', 'obey'], + difficulty: 'intermediate-advanced' + }, + breaks: { + enabled: true, + frequency: 15, + duration: 90 + } + }, + + media: { + videos: { + required: 10, + categories: 'user-preferences', + duration: { min: 15, max: 45 }, + preferenceWeight: 0.7 + }, + images: { + required: 15, + categories: 'user-preferences', + timing: 'throughout' + } + }, + + tasks: [ + { + type: 'marathon', + duration: 600, + phase: 'warm-up', + stroking: { + pace: 'gradual-build', + pattern: 'sustainable', + breaks: 'strategic' + }, + instructions: "Ten minute marathon warm-up. Pace yourself. Build arousal gradually." + }, + { + type: 'endurance', + duration: 480, + stroking: { + pace: 'steady-moderate', + pattern: 'consistent', + breaks: 'minimal' + }, + instructions: "Eight minutes steady stroking. Find your rhythm. Maintain it." + }, + { + type: 'edge', + count: 15, + duration: 180, + intensity: 'sustained', + instructions: "Fifteen edges over the session. Pace them out. Control is key.", + successCriteria: { + edges: 15, + cooldown: 90, + distribution: 'even' + } + }, + { + type: 'focus', + duration: 360, + target: 'extended-content', + instructions: "Six minutes pure focus. Watch longer videos. Let them draw you in.", + distractions: 'low', + arousal: 'sustained-high' + }, + { + type: 'pattern', + duration: 420, + pattern: { + sequence: 'marathon-sustainable', + complexity: 'moderate', + stamina: 'required' + }, + instructions: "Sustainable pattern for seven minutes. Conserve energy but stay aroused." + }, + { + type: 'denial', + duration: 300, + stroking: 'continuous', + edging: 'forbidden', + challenge: 'extended-stamina', + instructions: "Five minutes of denial. Stroke continuously but don't edge. Test your limits." + }, + { + type: 'obey', + commands: ['pace', 'sustain', 'breathe', 'hydrate'], + timing: 'stamina-support', + instructions: "Commands to help you maintain stamina. Follow them for best results." + } + ], + + objectives: [ + "Complete 50+ minute session", + "Achieve 15 edges evenly distributed", + "Demonstrate sustained arousal control" + ], + + rewards: { + xp: 400, + unlocks: ['Level 9'], + achievements: ['Endurance Champion'] + }, + + story: { + intro: "Extended sessions separate the committed from the casual. Today we build real stamina.", + checkpoint: null, + outro: "Impressive endurance. You're learning to sustain arousal for extended periods. This is true progress." + }, + + completion: { + required: { + tasksCompleted: 7, + edgesAchieved: 15, + marathonTime: 10, + timeSpent: 40 + }, + optional: { + fullDuration: 50, + perfectPacing: true + } + } + }, + + 9: { + levelNumber: 9, + arc: 2, + arcName: "Exploration", + title: "Advanced Techniques", + subtitle: "Mastering the Craft", + description: "Learn advanced edging techniques, complex patterns, and sophisticated arousal control methods.", + + session: { + duration: { min: 40, target: 45, max: 55 }, + tasks: { + total: 7, + types: ['technique', 'edge', 'pattern', 'focus', 'multi-task', 'challenge', 'obey'], + difficulty: 'advanced' + }, + breaks: { + enabled: true, + frequency: 12, + duration: 60 + } + }, + + media: { + videos: { + required: 10, + categories: 'advanced-content', + duration: { min: 15, max: 40 }, + preferenceWeight: 0.7 + }, + images: { + required: 15, + categories: 'advanced', + timing: 'technique-practice' + } + }, + + tasks: [ + { + type: 'technique', + duration: 420, + techniques: ['stop-start', 'squeeze', 'breathing', 'mental-control', 'grip-variation'], + instructions: "Learn and practice five advanced techniques. Master each one.", + practice: 'deliberate' + }, + { + type: 'edge', + count: 15, + duration: 240, + intensity: 'advanced', + techniques: 'apply-learned', + instructions: "Fifteen edges using advanced techniques. Show your mastery.", + successCriteria: { + edges: 15, + cooldown: 60, + techniqueVariety: 5 + } + }, + { + type: 'pattern', + duration: 360, + pattern: { + sequence: 'advanced-complex', + techniques: 'integrated', + precision: 'high' + }, + instructions: "Advanced pattern integrating multiple techniques. Precision required." + }, + { + type: 'focus', + duration: 300, + target: 'technique-application', + instructions: "Focus on applying techniques while watching. Mental and physical coordination.", + distractions: 'high', + coordination: 'required' + }, + { + type: 'multi-task', + duration: 360, + tasks: ['edge', 'focus', 'pattern'], + simultaneity: 'required', + instructions: "Multi-task challenge. Edge while maintaining focus and following pattern." + }, + { + type: 'challenge', + description: 'technique-mastery', + requirements: { + techniquesApplied: 5, + edgesWithTechnique: 10, + patternPrecision: 0.9 + }, + instructions: "Demonstrate mastery of all five techniques in combination." + }, + { + type: 'obey', + commands: ['apply-technique', 'switch-technique', 'combine', 'perfect'], + timing: 'technique-guidance', + instructions: "Commands will guide technique application. Execute perfectly." + } + ], + + objectives: [ + "Master 5 advanced edging techniques", + "Apply techniques in 15 edges", + "Demonstrate multi-tasking ability" + ], + + rewards: { + xp: 450, + unlocks: ['Level 10'], + achievements: ['Technique Master', 'Advanced Practitioner'] + }, + + story: { + intro: "You've learned the basics. Now we refine. Advanced techniques that separate the skilled from the masterful.", + checkpoint: null, + outro: "Exceptional technique work. You're no longer just edging - you're mastering the art of control." + }, + + completion: { + required: { + tasksCompleted: 7, + edgesAchieved: 15, + techniquesLearned: 5, + timeSpent: 40 + }, + optional: { + perfectTechniqueExecution: true, + allChallengesCompleted: true + } + } + }, + + 10: { + levelNumber: 10, + arc: 2, + arcName: "Exploration", + title: "Checkpoint: Major Milestone", + subtitle: "Prove Your Exploration", + description: "Arc 2 checkpoint. Demonstrate everything learned through exploration. Show your versatility, stamina, and technique mastery.", + + session: { + duration: { min: 50, target: 60, max: 75 }, + tasks: { + total: 9, + types: ['edge', 'endurance', 'technique', 'variety', 'focus', 'pattern', 'multi-task', 'challenge', 'obey'], + difficulty: 'advanced' + }, + breaks: { + enabled: true, + frequency: 15, + duration: 90 + } + }, + + media: { + videos: { + required: 12, + categories: 'user-preferences', + duration: { min: 10, max: 60 }, + preferenceWeight: 1.0 + }, + images: { + required: 20, + categories: 'user-preferences', + timing: 'throughout' + } + }, + + tasks: [ + { + type: 'edge', + count: 20, + duration: 300, + intensity: 'comprehensive', + variety: 'all-techniques', + instructions: "Twenty edges. Use all techniques learned. Show complete mastery.", + successCriteria: { + edges: 20, + cooldown: 60, + techniqueVariety: 5, + varietyRequired: true + } + }, + { + type: 'endurance', + duration: 600, + stroking: { + pace: 'varied-advanced', + pattern: 'complex', + breaks: 'strategic-minimal' + }, + instructions: "Ten minute endurance test. Demonstrate stamina and control." + }, + { + type: 'technique', + duration: 480, + techniques: 'all-advanced', + application: 'masterful', + instructions: "Eight minutes of technique demonstration. Show perfect execution." + }, + { + type: 'variety', + duration: 420, + modes: 'all-learned', + switching: 'fluid', + instructions: "Demonstrate versatility. Switch between all modes learned. Fluid transitions." + }, + { + type: 'focus', + duration: 420, + target: 'comprehensive-content', + instructions: "Seven minutes of intense focus. Varied content. Sustained arousal.", + distractions: 'extreme', + arousal: 'critical-sustained' + }, + { + type: 'pattern', + duration: 480, + pattern: { + sequence: 'checkpoint-complex', + techniques: 'all', + precision: 'maximum' + }, + instructions: "Most complex pattern yet. Integrate everything. Perfect execution." + }, + { + type: 'multi-task', + duration: 420, + tasks: 'all-types', + complexity: 'maximum', + instructions: "Ultimate multi-tasking. Edge, focus, pattern, obey - all simultaneously." + }, + { + type: 'challenge', + description: 'arc2-comprehensive', + requirements: { + edges: 20, + endurance: 10, + techniques: 5, + modes: 6, + multitasking: true, + perfectExecution: true + }, + instructions: "Final Arc 2 challenge. Everything you've learned. Perfect execution required." + }, + { + type: 'obey', + commands: 'comprehensive-all', + timing: 'complex-adaptive', + instructions: "All command types. Complex timing. Adaptive difficulty. Perfect obedience." + } + ], + + objectives: [ + "Complete 20 edges with all techniques", + "Demonstrate 10+ minutes endurance", + "Show mastery of all Arc 2 skills", + "Perfect multi-tasking performance" + ], + + rewards: { + xp: 750, + unlocks: ['Level 11', 'Arc 3: Dedication'], + achievements: ['Arc 2 Complete', 'Exploration Master', 'Major Milestone'], + bonuses: { + preferenceUpdate: true, + libraryAccess: 'full', + techniqueUnlocks: 'advanced-set' + } + }, + + story: { + intro: "Checkpoint 2. You've explored, experimented, and expanded your capabilities. Now prove your mastery of Arc 2.", + checkpoint: { + preferenceModal: true, + progressSummary: true, + statsDisplay: true, + achievementShowcase: true + }, + outro: "Outstanding performance. Arc 2: Exploration is complete. You've become versatile, skilled, and enduring. Arc 3: Dedication awaits - where true commitment is forged." + }, + + completion: { + required: { + tasksCompleted: 9, + edgesAchieved: 20, + enduranceTime: 10, + techniquesApplied: 5, + timeSpent: 50 + }, + optional: { + perfectScore: true, + allBonusesEarned: true, + recordBreaking: true + } + } + }, + + // ARC 3: DEDICATION (Levels 11-15) + 11: { + levelNumber: 11, + arc: 3, + arcName: "Dedication", + title: "Commitment", + subtitle: "True Dedication Begins", + description: "Arc 3: Dedication. This is where casual participants fall away. Only the truly committed continue. Prove your dedication.", + + session: { + duration: { min: 50, target: 60, max: 70 }, + tasks: { + total: 8, + types: ['commitment', 'edge', 'endurance', 'discipline', 'focus', 'sacrifice', 'obey', 'challenge'], + difficulty: 'advanced' + }, + breaks: { + enabled: true, + frequency: 15, + duration: 60 + } + }, + + media: { + videos: { + required: 12, + categories: ['intense', 'demanding', 'commitment-focused'], + duration: { min: 15, max: 50 }, + preferenceWeight: 0.7 + }, + images: { + required: 20, + categories: ['intense', 'demanding'], + timing: 'throughout' + } + }, + + tasks: [ + { + type: 'commitment', + duration: 720, + phase: 'dedication-test', + requirements: { + consistentArousal: true, + noBackingDown: true, + fullAttention: true + }, + instructions: "Twelve minutes of pure commitment. No breaks. No hesitation. Full dedication." + }, + { + type: 'edge', + count: 20, + duration: 240, + intensity: 'demanding', + commitment: 'required', + instructions: "Twenty edges. Prove your commitment to the training. No shortcuts.", + successCriteria: { + edges: 20, + cooldown: 60, + perfectControl: true + } + }, + { + type: 'endurance', + duration: 720, + stroking: { + pace: 'challenging', + pattern: 'sustained-difficult', + breaks: 'none' + }, + instructions: "Twelve minutes continuous. No breaks. This is where dedication shows." + }, + { + type: 'discipline', + duration: 360, + rules: ['no-stopping', 'maintain-pace', 'follow-commands', 'no-edge'], + instructions: "Discipline test. Stroke continuously. Follow all rules. Never edge." + }, + { + type: 'focus', + duration: 480, + target: 'challenging-content', + instructions: "Eight minutes intense focus. Challenging content. Maintain arousal. No breaks.", + distractions: 'extreme', + arousal: 'critical-sustained' + }, + { + type: 'sacrifice', + duration: 300, + give: 'comfort', + gain: 'progress', + instructions: "Sacrifice comfort for progress. Challenging positions, difficult pace. Dedication requires sacrifice." + }, + { + type: 'challenge', + description: 'dedication-proof', + requirements: { + commitmentTime: 12, + edges: 20, + endurance: 12, + disciplineScore: 0.95 + }, + instructions: "Prove your dedication. Complete all requirements without wavering." + }, + { + type: 'obey', + commands: ['commit', 'endure', 'sacrifice', 'persist'], + timing: 'demanding', + instructions: "Commands will push you. Obey without hesitation. Show your dedication." + } + ], + + objectives: [ + "Complete 12+ minute commitment session", + "Achieve 20 perfect edges", + "Demonstrate unwavering discipline", + "Make meaningful sacrifices for progress" + ], + + rewards: { + xp: 500, + unlocks: ['Level 12'], + achievements: ['Dedicated Student'] + }, + + story: { + intro: "Welcome to Arc 3: Dedication. This is where we separate those who play from those who commit. Are you truly dedicated?", + checkpoint: null, + outro: "You've proven your dedication. This level of commitment will carry you through the challenges ahead." + }, + + completion: { + required: { + tasksCompleted: 8, + edgesAchieved: 20, + commitmentTime: 12, + enduranceTime: 12, + disciplineScore: 0.9, + timeSpent: 50 + }, + optional: { + perfectDedication: true, + noBackingDown: true + } + } + }, + + 12: { + levelNumber: 12, + arc: 3, + arcName: "Dedication", + title: "Deeper Commitment", + subtitle: "Beyond Your Limits", + description: "Push beyond what you thought possible. True dedication means going further than you've ever gone.", + + session: { + duration: { min: 55, target: 65, max: 75 }, + tasks: { + total: 8, + types: ['push-limits', 'edge', 'endurance', 'mental-strength', 'focus', 'perseverance', 'challenge', 'obey'], + difficulty: 'advanced' + }, + breaks: { + enabled: true, + frequency: 18, + duration: 90 + } + }, + + media: { + videos: { + required: 14, + categories: ['extreme', 'pushing-boundaries'], + duration: { min: 20, max: 60 }, + preferenceWeight: 0.7 + }, + images: { + required: 22, + categories: ['extreme', 'intense'], + timing: 'limit-pushing' + } + }, + + tasks: [ + { + type: 'push-limits', + duration: 900, + beyond: 'comfort-zone', + requirements: { + longerThanBefore: true, + harderThanBefore: true, + deeperThanBefore: true + }, + instructions: "Fifteen minutes pushing your limits. Go beyond. This is growth." + }, + { + type: 'edge', + count: 25, + duration: 300, + intensity: 'extreme', + limitPushing: 'required', + instructions: "Twenty-five edges. More than ever before. Push your control limits.", + successCriteria: { + edges: 25, + cooldown: 50, + newPersonalBest: true + } + }, + { + type: 'endurance', + duration: 900, + stroking: { + pace: 'extreme', + pattern: 'relentless', + breaks: 'none' + }, + instructions: "Fifteen minutes continuous. Your longest yet. Endure." + }, + { + type: 'mental-strength', + duration: 420, + challenges: ['pain', 'exhaustion', 'doubt', 'temptation'], + overcome: 'all', + instructions: "Mental strength test. Overcome pain, exhaustion, doubt. Your mind is stronger than you think." + }, + { + type: 'focus', + duration: 540, + target: 'extreme-content', + instructions: "Nine minutes extreme focus. Beyond your previous limits.", + distractions: 'maximum', + arousal: 'beyond-critical' + }, + { + type: 'perseverance', + duration: 600, + difficulty: 'increasing', + quitAllowed: 'no', + instructions: "Ten minutes of increasing difficulty. Quitting is not an option. Persevere." + }, + { + type: 'challenge', + description: 'limit-breaking', + requirements: { + personalBests: 3, + edges: 25, + endurance: 15, + mentalStrength: 0.95 + }, + instructions: "Break your personal limits. Set new records. This is dedication." + }, + { + type: 'obey', + commands: ['push', 'endure', 'overcome', 'persist'], + timing: 'relentless', + instructions: "Commands will push you to your limits. Obey. Do not break." + } + ], + + objectives: [ + "Push beyond previous limits in 3+ areas", + "Achieve 25 edges - new personal best", + "Complete 15 minute endurance", + "Demonstrate unbreakable mental strength" + ], + + rewards: { + xp: 550, + unlocks: ['Level 13'], + achievements: ['Limit Breaker'] + }, + + story: { + intro: "Dedication means pushing limits. Today you go further than ever before. Find strength you didn't know you had.", + checkpoint: null, + outro: "You've broken through barriers. What once seemed impossible is now achieved. This is real growth." + }, + + completion: { + required: { + tasksCompleted: 8, + edgesAchieved: 25, + enduranceTime: 15, + personalBests: 3, + timeSpent: 55 + }, + optional: { + unbroken: true, + recordBreaking: true + } + } + }, + + 13: { + levelNumber: 13, + arc: 3, + arcName: "Dedication", + title: "Sustained Excellence", + subtitle: "Consistency is Key", + description: "Excellence isn't a one-time achievement. Maintain peak performance throughout an extended session.", + + session: { + duration: { min: 60, target: 70, max: 85 }, + tasks: { + total: 9, + types: ['sustained', 'edge', 'endurance', 'consistency', 'focus', 'performance', 'marathon', 'challenge', 'obey'], + difficulty: 'advanced-expert' + }, + breaks: { + enabled: true, + frequency: 20, + duration: 120 + } + }, + + media: { + videos: { + required: 15, + categories: 'user-preferences', + duration: { min: 20, max: 70 }, + preferenceWeight: 0.8 + }, + images: { + required: 25, + categories: 'user-preferences', + timing: 'sustained' + } + }, + + tasks: [ + { + type: 'sustained', + duration: 1200, + performance: 'peak', + consistency: 'required', + instructions: "Twenty minutes of sustained peak performance. No drops in quality. Consistent excellence." + }, + { + type: 'edge', + count: 30, + duration: 600, + intensity: 'sustained-high', + distribution: 'even', + instructions: "Thirty edges over ten minutes. Evenly paced. Perfect consistency.", + successCriteria: { + edges: 30, + cooldown: 15, + evenDistribution: true, + qualityConsistent: true + } + }, + { + type: 'endurance', + duration: 1200, + stroking: { + pace: 'consistent-high', + pattern: 'marathon', + breaks: 'strategic-minimal' + }, + instructions: "Twenty minutes marathon endurance. Pace yourself. Maintain quality." + }, + { + type: 'consistency', + duration: 720, + metrics: ['arousal', 'pace', 'focus', 'quality'], + variance: 'minimal', + instructions: "Twelve minutes of perfect consistency. No peaks and valleys. Steady excellence." + }, + { + type: 'focus', + duration: 600, + target: 'extended-content', + instructions: "Ten minutes sustained focus. Long content. Maintained attention.", + distractions: 'high', + arousal: 'sustained-critical' + }, + { + type: 'performance', + duration: 480, + standard: 'peak', + sustained: 'required', + instructions: "Eight minutes peak performance. Every second counts. No drops." + }, + { + type: 'marathon', + duration: 1500, + phase: 'middle-arc', + pacing: 'expert', + instructions: "Twenty-five minute marathon. Expert pacing required. This is Arc 3." + }, + { + type: 'challenge', + description: 'sustained-excellence', + requirements: { + sessionDuration: 60, + edges: 30, + endurance: 20, + consistencyScore: 0.95, + noPerformanceDrops: true + }, + instructions: "Maintain excellence for the full session. No drops. No breaks in quality." + }, + { + type: 'obey', + commands: ['sustain', 'maintain', 'consistent', 'steady'], + timing: 'consistency-support', + instructions: "Commands to help maintain consistency. Follow precisely." + } + ], + + objectives: [ + "Maintain peak performance for 60+ minutes", + "Complete 30 evenly-paced edges", + "Achieve 95%+ consistency score", + "Complete marathon session without quality drops" + ], + + rewards: { + xp: 600, + unlocks: ['Level 14'], + achievements: ['Consistency Champion', 'Marathon Runner'] + }, + + story: { + intro: "Anyone can excel once. True dedication is sustained excellence. Today you prove you can maintain peak performance.", + checkpoint: null, + outro: "Impressive consistency. You've shown that your dedication isn't fleeting - it's sustained and reliable." + }, + + completion: { + required: { + tasksCompleted: 9, + edgesAchieved: 30, + enduranceTime: 20, + marathonTime: 25, + consistencyScore: 0.9, + timeSpent: 60 + }, + optional: { + perfectConsistency: true, + recordMarathon: true + } + } + }, + + 14: { + levelNumber: 14, + arc: 3, + arcName: "Dedication", + title: "Total Immersion", + subtitle: "Complete Dedication", + description: "Total immersion in your training. Mind, body, and will completely dedicated to the session.", + + session: { + duration: { min: 65, target: 75, max: 90 }, + tasks: { + total: 9, + types: ['immersion', 'edge', 'trance', 'dedication', 'focus', 'surrender', 'transformation', 'challenge', 'obey'], + difficulty: 'expert' + }, + breaks: { + enabled: true, + frequency: 20, + duration: 90 + } + }, + + media: { + videos: { + required: 16, + categories: ['immersive', 'hypnotic', 'transformative'], + duration: { min: 20, max: 75 }, + preferenceWeight: 0.8 + }, + images: { + required: 28, + categories: ['immersive', 'hypnotic'], + timing: 'trance-induction' + } + }, + + tasks: [ + { + type: 'immersion', + duration: 1800, + depth: 'total', + aspects: ['visual', 'mental', 'physical', 'emotional'], + instructions: "Thirty minutes total immersion. Let the training consume you completely." + }, + { + type: 'edge', + count: 35, + duration: 720, + intensity: 'immersive', + mindState: 'trance', + instructions: "Thirty-five edges in a state of deep immersion. Let go. Let the training guide you.", + successCriteria: { + edges: 35, + cooldown: 10, + tranceState: true + } + }, + { + type: 'trance', + duration: 900, + depth: 'deep', + maintenance: 'sustained', + instructions: "Fifteen minutes in trance. Let your mind sink. Stay in this state." + }, + { + type: 'dedication', + duration: 600, + level: 'total', + aspects: 'all', + instructions: "Ten minutes of total dedication. Nothing else exists. Only the training." + }, + { + type: 'focus', + duration: 720, + target: 'immersive-content', + instructions: "Twelve minutes immersed in content. Let it fill your awareness completely.", + distractions: 'none-internal', + arousal: 'trance-maintained' + }, + { + type: 'surrender', + duration: 480, + to: 'training', + resistance: 'none', + instructions: "Surrender to the training. Stop fighting. Let it guide you completely." + }, + { + type: 'transformation', + duration: 600, + from: 'resistant', + to: 'devoted', + instructions: "Feel yourself transforming. Resistance melts. Devotion grows. This is your path." + }, + { + type: 'challenge', + description: 'total-immersion', + requirements: { + immersionTime: 30, + edges: 35, + tranceDepth: 0.9, + surrenderComplete: true + }, + instructions: "Achieve total immersion. Complete surrender. Deep transformation." + }, + { + type: 'obey', + commands: ['immerse', 'surrender', 'transform', 'become'], + timing: 'trance-deepening', + instructions: "Commands to deepen your immersion. Obey without thought. Let go." + } + ], + + objectives: [ + "Achieve 30 minutes total immersion", + "Complete 35 edges in trance state", + "Demonstrate complete surrender", + "Show transformation in dedication" + ], + + rewards: { + xp: 650, + unlocks: ['Level 15'], + achievements: ['Fully Immersed', 'Devoted Student'] + }, + + story: { + intro: "True dedication requires total immersion. Today you stop holding back. You surrender to the training completely.", + checkpoint: null, + outro: "You've experienced total immersion. This level of dedication transforms you. You're no longer the same person who started." + }, + + completion: { + required: { + tasksCompleted: 9, + edgesAchieved: 35, + immersionTime: 30, + tranceTime: 15, + surrenderComplete: true, + timeSpent: 65 + }, + optional: { + deepestTrance: true, + completeTransformation: true + } + } + }, + + 15: { + levelNumber: 15, + arc: 3, + arcName: "Dedication", + title: "Checkpoint: Mid-Point Mastery", + subtitle: "Halfway to Excellence", + description: "Checkpoint 3 - the midpoint of your journey. Demonstrate your dedication, consistency, and transformation. Update preferences and review progress.", + + session: { + duration: { min: 70, target: 90, max: 120 }, + tasks: { + total: 10, + types: ['comprehensive', 'edge', 'endurance', 'dedication', 'immersion', 'focus', 'transformation', 'marathon', 'challenge', 'obey'], + difficulty: 'expert' + }, + breaks: { + enabled: true, + frequency: 25, + duration: 120 + } + }, + + media: { + videos: { + required: 20, + categories: 'user-preferences', + duration: { min: 15, max: 90 }, + preferenceWeight: 1.0 + }, + images: { + required: 35, + categories: 'user-preferences', + timing: 'throughout' + } + }, + + tasks: [ + { + type: 'comprehensive', + duration: 2700, + phase: 'midpoint-assessment', + aspects: 'all-arc3', + instructions: "Forty-five minute comprehensive session. All Arc 3 skills. Complete demonstration." + }, + { + type: 'edge', + count: 50, + duration: 1200, + intensity: 'comprehensive', + variety: 'all-learned', + instructions: "Fifty edges. Your greatest challenge yet. All techniques. Perfect execution.", + successCriteria: { + edges: 50, + cooldown: 10, + techniqueVariety: 'all', + perfectControl: true + } + }, + { + type: 'endurance', + duration: 1800, + stroking: { + pace: 'expert-level', + pattern: 'comprehensive', + breaks: 'strategic' + }, + instructions: "Thirty minutes endurance. Demonstrate mastery of pacing and stamina." + }, + { + type: 'dedication', + duration: 1200, + proof: 'comprehensive', + aspects: 'all', + instructions: "Twenty minutes proving your dedication. Everything you've learned in Arc 3." + }, + { + type: 'immersion', + duration: 1500, + depth: 'maximum', + maintenance: 'full-session', + instructions: "Twenty-five minutes deep immersion. Maintain trance state throughout." + }, + { + type: 'focus', + duration: 900, + target: 'comprehensive-preferred', + instructions: "Fifteen minutes peak focus. Your favorite content. Complete absorption.", + distractions: 'none', + arousal: 'maximum-controlled' + }, + { + type: 'transformation', + duration: 720, + showcase: 'journey', + fromStartToNow: true, + instructions: "Reflect on your transformation. From Level 1 to Level 15. How far you've come." + }, + { + type: 'marathon', + duration: 3600, + phase: 'midpoint-ultimate', + expertise: 'demonstrated', + instructions: "One hour marathon. Your ultimate test. Expert-level pacing and control." + }, + { + type: 'challenge', + description: 'arc3-mastery', + requirements: { + sessionDuration: 70, + edges: 50, + endurance: 30, + immersion: 25, + dedication: 20, + marathonComplete: 60, + perfectExecution: true + }, + instructions: "Demonstrate complete mastery of Arc 3: Dedication. All skills. Perfect execution." + }, + { + type: 'obey', + commands: 'comprehensive-all', + timing: 'expert-adaptive', + instructions: "All commands. Expert timing. Complete obedience. Perfect execution." + } + ], + + objectives: [ + "Complete 70+ minute comprehensive session", + "Achieve 50 perfect edges", + "Demonstrate 30 minutes endurance", + "Complete 60 minute marathon", + "Show complete Arc 3 mastery" + ], + + rewards: { + xp: 1000, + unlocks: ['Level 16', 'Arc 4: Transformation'], + achievements: ['Arc 3 Complete', 'Dedicated Master', 'Midpoint Champion', 'Halfway to Excellence'], + bonuses: { + preferenceUpdate: true, + libraryAccess: 'premium', + techniqueUnlocks: 'expert-set', + transformationBadge: true + } + }, + + story: { + intro: "Checkpoint 3. The midpoint. You've come so far. From beginner to dedicated expert. Now prove everything you've learned.", + checkpoint: { + preferenceModal: true, + progressSummary: true, + statsDisplay: true, + achievementShowcase: true, + transformationReview: true + }, + outro: "Extraordinary. Arc 3: Dedication is complete. You're halfway through your journey. The foundation is solid. The dedication is proven. Arc 4: Transformation awaits - where you become something more." + }, + + completion: { + required: { + tasksCompleted: 10, + edgesAchieved: 50, + enduranceTime: 30, + immersionTime: 25, + marathonTime: 60, + timeSpent: 70 + }, + optional: { + perfectScore: true, + recordBreaking: true, + allBonusesEarned: true, + legendaryPerformance: true + } + } + }, + + // ARC 4: TRANSFORMATION (Levels 16-20) + 16: { + levelNumber: 16, + arc: 4, + arcName: "Transformation", + title: "Evolution", + subtitle: "Becoming Something More", + description: "Arc 4: Transformation. You're no longer who you were. Now you evolve into what you're meant to become.", + + session: { + duration: { min: 70, target: 80, max: 100 }, + tasks: { + total: 9, + types: ['evolution', 'edge', 'identity', 'reshaping', 'focus', 'acceptance', 'becoming', 'challenge', 'obey'], + difficulty: 'expert' + }, + breaks: { + enabled: true, + frequency: 20, + duration: 90 + } + }, + + media: { + videos: { + required: 18, + categories: ['transformative', 'identity-focused', 'evolution'], + duration: { min: 20, max: 80 }, + preferenceWeight: 0.8 + }, + images: { + required: 30, + categories: ['transformative', 'powerful'], + timing: 'transformation-moments' + } + }, + + tasks: [ + { + type: 'evolution', + duration: 1200, + from: 'old-self', + to: 'new-self', + process: 'conscious', + instructions: "Twenty minutes of conscious evolution. Feel yourself changing. Becoming." + }, + { + type: 'edge', + count: 40, + duration: 900, + intensity: 'transformative', + meaning: 'evolution', + instructions: "Forty edges that transform you. Each one changes you slightly. By the end, you're different.", + successCriteria: { + edges: 40, + cooldown: 15, + transformationFelt: true + } + }, + { + type: 'identity', + duration: 720, + exploration: 'deep', + reshaping: 'active', + instructions: "Who are you becoming? Explore your evolving identity. Accept the changes." + }, + { + type: 'reshaping', + duration: 600, + aspects: ['desires', 'preferences', 'responses', 'identity'], + instructions: "Active reshaping. Your desires evolve. Your responses change. This is transformation." + }, + { + type: 'focus', + duration: 720, + target: 'transformative-content', + instructions: "Focus on content that transforms you. Let it reshape your desires.", + distractions: 'internal-resistance', + arousal: 'transformative' + }, + { + type: 'acceptance', + duration: 480, + of: 'transformation', + resistance: 'release', + instructions: "Accept your transformation. Stop resisting. This is who you're becoming." + }, + { + type: 'becoming', + duration: 900, + process: 'active', + awareness: 'maintained', + instructions: "Fifteen minutes of active becoming. Watch yourself transform. Feel it happening." + }, + { + type: 'challenge', + description: 'transformation-proof', + requirements: { + evolutionTime: 20, + edges: 40, + identityExploration: true, + acceptanceComplete: true + }, + instructions: "Prove your transformation is real. Show how you've changed." + }, + { + type: 'obey', + commands: ['evolve', 'transform', 'become', 'accept'], + timing: 'transformation-support', + instructions: "Commands to guide your transformation. Obey. Let them reshape you." + } + ], + + objectives: [ + "Complete 20 minutes conscious evolution", + "Achieve 40 transformative edges", + "Demonstrate identity exploration", + "Show complete acceptance of transformation" + ], + + rewards: { + xp: 700, + unlocks: ['Level 17'], + achievements: ['Evolved Being'] + }, + + story: { + intro: "Welcome to Arc 4: Transformation. The second half of your journey begins. You're no longer the person who started. Now you actively shape who you're becoming.", + checkpoint: null, + outro: "You feel it, don't you? The transformation is real. You're evolving into something more." + }, + + completion: { + required: { + tasksCompleted: 9, + edgesAchieved: 40, + evolutionTime: 20, + acceptanceShown: true, + timeSpent: 70 + }, + optional: { + deepTransformation: true, + resistanceGone: true + } + } + } + + // Levels 17-30 generated programmatically + }; + + // Merge manually configured levels with generated ones + return { ...manualLevels, ...this.generateRemainingLevels() }; + } + + /** + * Generate remaining levels programmatically + * Levels 17-30 follow progression patterns with increasing difficulty + */ + generateRemainingLevels() { + const remaining = {}; + + // Arc 4 completion (17-20) + const arc4Levels = [ + { num: 17, title: "Deep Changes", edges: 45, duration: 75 }, + { num: 18, title: "New Identity", edges: 50, duration: 80 }, + { num: 19, title: "Living Transformed", edges: 55, duration: 85 }, + { num: 20, title: "Checkpoint: Transformation Complete", edges: 75, duration: 90, checkpoint: true } + ]; + + // Arc 5: Mastery (21-25) + const arc5Levels = [ + { num: 21, title: "Advanced Training", edges: 60, duration: 90 }, + { num: 22, title: "Perfecting Technique", edges: 65, duration: 95 }, + { num: 23, title: "Expert Performance", edges: 70, duration: 100 }, + { num: 24, title: "Near Perfection", edges: 75, duration: 105 }, + { num: 25, title: "Checkpoint: Mastery Achieved", edges: 100, duration: 120, checkpoint: true } + ]; + + // Arc 6: Transcendence (26-30) + const arc6Levels = [ + { num: 26, title: "Expert Trials", edges: 80, duration: 110 }, + { num: 27, title: "Beyond Limits", edges: 90, duration: 120 }, + { num: 28, title: "Peak Performance", edges: 100, duration: 130 }, + { num: 29, title: "Ultimate Challenge", edges: 120, duration: 150 }, + { num: 30, title: "Final Checkpoint: Ultimate Achievement", edges: 150, duration: 180, checkpoint: true } + ]; + + [...arc4Levels, ...arc5Levels, ...arc6Levels].forEach(level => { + const arcNum = level.num <= 20 ? 4 : (level.num <= 25 ? 5 : 6); + const arcName = arcNum === 4 ? "Transformation" : (arcNum === 5 ? "Mastery" : "Transcendence"); + + remaining[level.num] = { + levelNumber: level.num, + arc: arcNum, + arcName: arcName, + title: level.title, + subtitle: `Arc ${arcNum} Progress`, + description: `Level ${level.num} of The Academy training program.`, + + session: { + duration: { min: level.duration - 10, target: level.duration, max: level.duration + 20 }, + tasks: { + total: 8 + Math.floor(level.num / 5), + types: ['edge', 'endurance', 'focus', 'pattern', 'obey', 'challenge'], + difficulty: level.num < 21 ? 'expert' : (level.num < 26 ? 'master' : 'transcendent') + }, + breaks: { + enabled: true, + frequency: 15 + Math.floor(level.num / 3), + duration: 90 + (level.num * 2) + } + }, + + media: { + videos: { + required: 10 + level.num, + categories: level.checkpoint ? 'user-preferences' : 'advanced', + duration: { min: 15 + level.num, max: 30 + (level.num * 2) }, + preferenceWeight: level.checkpoint ? 1.0 : 0.7 + (level.num * 0.01) + }, + images: { + required: 15 + (level.num * 2), + categories: level.checkpoint ? 'user-preferences' : 'advanced', + timing: 'throughout' + } + }, + + tasks: [ + { + type: 'edge', + count: level.edges, + duration: 300 + (level.num * 30), + intensity: 'progressive', + instructions: `Complete ${level.edges} edges demonstrating your mastery.`, + successCriteria: { + edges: level.edges, + cooldown: Math.max(10, 60 - level.num), + perfectControl: true + } + } + ], + + objectives: [ + `Complete ${level.edges} perfect edges`, + `Demonstrate Arc ${arcNum} skills`, + `Maintain ${level.duration}+ minute session` + ], + + rewards: { + xp: 500 + (level.num * 50), + unlocks: level.num < 30 ? [`Level ${level.num + 1}`] : ['Academy Complete'], + achievements: level.checkpoint ? [`Arc ${arcNum} Complete`, `Level ${level.num} Master`] : [`Level ${level.num} Complete`] + }, + + story: { + intro: `Level ${level.num}: ${level.title}. ${level.checkpoint ? 'Checkpoint - demonstrate everything learned.' : 'Continue your progression through Arc ' + arcNum + '.'}`, + checkpoint: level.checkpoint ? { + preferenceModal: true, + progressSummary: true, + statsDisplay: true + } : null, + outro: level.checkpoint ? `Arc ${arcNum} complete! ${level.num === 30 ? 'Congratulations on completing The Academy!' : 'Prepare for Arc ' + (arcNum + 1) + '.'}` : `Level ${level.num} complete. Excellent progress.` + }, + + completion: { + required: { + tasksCompleted: 1, + edgesAchieved: level.edges, + timeSpent: level.duration - 10 + }, + optional: { + perfectScore: true, + recordBreaking: level.checkpoint + } + } + }; + }); + + return remaining; + } + + /** + * Get media requirements for a level based on user preferences + * @param {number} levelNumber + * @param {Object} userPreferences + * @returns {Object} Filtered media config + */ + getMediaForLevel(levelNumber, userPreferences) { + const levelConfig = this.getLevelConfig(levelNumber); + if (!levelConfig) return null; + + const mediaConfig = levelConfig.media; + const preferenceWeight = mediaConfig.videos.preferenceWeight; + + // Build content filter + const filter = { + tags: [], + excludeTags: [], + minRating: 0, + duration: mediaConfig.videos.duration + }; + + // Apply level requirements + if (Array.isArray(mediaConfig.videos.categories)) { + filter.tags = [...mediaConfig.videos.categories]; + } + + // Blend with user preferences based on preference weight + if (preferenceWeight > 0 && userPreferences) { + const userFilter = window.preferenceManager.getContentFilter(); + + // Merge tags with preference weight + if (userFilter.tags.length > 0) { + const userTagCount = Math.floor(userFilter.tags.length * preferenceWeight); + const levelTagCount = filter.tags.length; + + // Take percentage of user tags based on weight + const selectedUserTags = userFilter.tags.slice(0, userTagCount); + filter.tags = [...filter.tags, ...selectedUserTags]; + } + + // Apply user exclusions + if (userFilter.excludeTags) { + filter.excludeTags = userFilter.excludeTags; + } + } + + return { + videoFilter: filter, + videoCount: mediaConfig.videos.required, + imageFilter: { tags: mediaConfig.images.categories }, + imageCount: mediaConfig.images.required + }; + } + + /** + * Calculate level difficulty score + * @param {number} levelNumber + * @returns {number} Difficulty score 0-100 + */ + getDifficultyScore(levelNumber) { + const levelConfig = this.getLevelConfig(levelNumber); + if (!levelConfig) return 0; + + let score = 0; + + // Base score from level number + score += (levelNumber - 1) * 2; // 0-58 points + + // Task complexity + score += levelConfig.session.tasks.total * 2; // Task count + + // Duration + const targetDuration = levelConfig.session.duration.target; + score += Math.min(targetDuration / 2, 20); // Up to 20 points for duration + + // Edge count + const edgeTask = levelConfig.tasks.find(t => t.type === 'edge'); + if (edgeTask) { + score += Math.min(edgeTask.count, 15); // Up to 15 points for edges + } + + return Math.min(Math.round(score), 100); + } +} + +// Initialize and expose globally +window.academyLevelData = new AcademyLevelData(); +console.log('📚 Academy Level Data initialized - Levels 1-5 configured'); diff --git a/src/features/academy/academyUI.js b/src/features/academy/academyUI.js new file mode 100644 index 0000000..ee99ade --- /dev/null +++ b/src/features/academy/academyUI.js @@ -0,0 +1,590 @@ +/** + * Academy UI Manager + * Handles level selection, checkpoint modals, and integration with campaign/preference/library systems + */ + +class AcademyUI { + constructor() { + this.currentModal = null; + this.init(); + } + + init() { + console.log('🎓 Academy UI Manager initialized'); + } + + /** + * Show level selection screen + * Displays all 30 levels with locked/unlocked states + */ + showLevelSelect() { + const unlockedLevels = window.campaignManager.getUnlockedLevels(); + const completedLevels = window.gameData.academyProgress.completedLevels; + const currentLevel = window.gameData.academyProgress.currentLevel; + + let html = ` +
+
+

🎓 The Academy - Campaign

+

Select your next level

+
+
+
+
+

${completedLevels.length}/30 Levels Complete

+
+
+ +
+ `; + + // Generate 30 level buttons + for (let i = 1; i <= 30; i++) { + const isUnlocked = unlockedLevels.includes(i); + const isCompleted = completedLevels.includes(i); + const isCurrent = i === currentLevel; + const isCheckpoint = window.campaignManager.isCheckpointLevel(i); + const arc = window.campaignManager.getArcForLevel(i); + + const statusClass = isCompleted ? 'completed' : + isUnlocked ? 'unlocked' : 'locked'; + + const icon = isCompleted ? '✓' : + isCheckpoint ? '⚡' : + isUnlocked ? '▶' : '🔒'; + + html += ` + + `; + } + + html += ` +
+ +
+

Select a level to view details

+
+ + +
+ `; + + // Show in the academy setup container + const setupContainer = document.getElementById('academy-setup'); + if (setupContainer) { + setupContainer.innerHTML = html; + setupContainer.style.display = 'block'; + } + } + + /** + * Select a level and show its details + * @param {number} levelNum - Level to select + */ + selectLevel(levelNum) { + const arc = window.campaignManager.getArcForLevel(levelNum); + const isCheckpoint = window.campaignManager.isCheckpointLevel(levelNum); + const isCompleted = window.campaignManager.isLevelCompleted(levelNum); + + // Show level details in info panel + const infoPanelContent = this.getLevelInfoHTML(levelNum, arc, isCheckpoint, isCompleted); + const infoPanel = document.getElementById('level-info-panel'); + if (infoPanel) { + infoPanel.innerHTML = infoPanelContent; + } + } + + /** + * Get level info HTML + * @param {number} levelNum - Level number + * @param {string} arc - Arc name + * @param {boolean} isCheckpoint - Is checkpoint level + * @param {boolean} isCompleted - Is completed + * @returns {string} HTML content + */ + getLevelInfoHTML(levelNum, arc, isCheckpoint, isCompleted) { + return ` +
+

Level ${levelNum}: ${this.getLevelTitle(levelNum)}

+
+ ${arc} Arc + ${isCheckpoint ? '⚡ Checkpoint' : ''} + ${isCompleted ? '✓ Completed' : ''} +
+

${this.getLevelDescription(levelNum)}

+ ${isCheckpoint ? '

💡 You will be asked to update your preferences before starting this level.

' : ''} + +
+ `; + } + + /** + * Get level title based on number + * @param {number} levelNum - Level number + * @returns {string} Level title + */ + getLevelTitle(levelNum) { + const titles = { + 1: "First Edge", + 5: "Foundation Complete", + 10: "Feature Discovery Complete", + 15: "Deepening", + 20: "Mastery", + 25: "Final Challenge", + 30: "Graduation" + }; + return titles[levelNum] || `Training Session ${levelNum}`; + } + + /** + * Get level description + * @param {number} levelNum - Level number + * @returns {string} Level description + */ + getLevelDescription(levelNum) { + if (levelNum === 1) return "Welcome to The Academy. Begin your journey with basic edging training."; + if (levelNum === 5) return "Complete the Foundation arc. Test your progress with a checkpoint session."; + if (levelNum === 10) return "Feature Discovery complete. Time to optimize your preferences."; + if (levelNum === 15) return "Halfway through. Deepen your training with advanced techniques."; + if (levelNum === 20) return "Enter the Mastery arc. Push your limits further."; + if (levelNum === 25) return "Final checkpoint before graduation. Prepare for the ultimate test."; + if (levelNum === 30) return "The final test. Graduate from The Academy."; + return "Continue your training journey with this session."; + } + + /** + * Start a level (with checkpoint modal if needed) + * @param {number} levelNum - Level to start + */ + startLevel(levelNum) { + console.log(`🎯 Starting Level ${levelNum}...`); + + // Check if this is a checkpoint level + if (window.campaignManager.isCheckpointLevel(levelNum)) { + this.showCheckpointModal(levelNum); + } else { + this.beginLevel(levelNum); + } + } + + /** + * Show checkpoint preference modal + * @param {number} levelNum - Checkpoint level number + */ + showCheckpointModal(levelNum) { + const config = window.preferenceManager.getCheckpointModalConfig(levelNum); + + if (!config) { + console.error('No checkpoint config for level', levelNum); + this.beginLevel(levelNum); + return; + } + + const modalHTML = this.buildCheckpointModalHTML(levelNum, config); + + // Create modal overlay + const overlay = document.createElement('div'); + overlay.className = 'checkpoint-modal-overlay'; + overlay.innerHTML = modalHTML; + document.body.appendChild(overlay); + + this.currentModal = overlay; + + // Initialize tabs + this.initCheckpointModalTabs(levelNum, config); + } + + /** + * Build checkpoint modal HTML + * @param {number} levelNum - Level number + * @param {Object} config - Modal configuration + * @returns {string} Modal HTML + */ + buildCheckpointModalHTML(levelNum, config) { + return ` +
+
+

${config.title}

+

${config.description}

+
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ + +
+ `; + } + + /** + * Initialize checkpoint modal tabs + * @param {number} levelNum - Level number + * @param {Object} config - Modal configuration + */ + initCheckpointModalTabs(levelNum, config) { + // Tab switching + const tabBtns = document.querySelectorAll('.tab-btn'); + tabBtns.forEach(btn => { + btn.addEventListener('click', () => { + const tabName = btn.dataset.tab; + + // Update active states + tabBtns.forEach(b => b.classList.remove('active')); + btn.classList.add('active'); + + document.querySelectorAll('.tab-panel').forEach(panel => { + panel.classList.remove('active'); + }); + document.getElementById(`${tabName}-panel`).classList.add('active'); + }); + }); + + // Populate preferences editor + this.populatePreferencesEditor(config.categories); + + // Populate library manager + this.populateLibraryManager(); + } + + /** + * Populate preferences editor + * @param {Array} categories - Categories to show + */ + populatePreferencesEditor(categories) { + const container = document.getElementById('preferences-editor'); + if (!container) return; + + let html = ''; + + categories.forEach(category => { + const prefs = window.preferenceManager.getCategoryPreferences(category); + html += `
`; + html += `

${this.getCategoryDisplayName(category)}

`; + html += this.buildCategoryEditor(category, prefs); + html += `
`; + }); + + container.innerHTML = html; + } + + /** + * Get category display name + * @param {string} category - Category key + * @returns {string} Display name + */ + getCategoryDisplayName(category) { + const names = { + contentThemes: '🎭 Content Themes', + visualPreferences: '👁️ Visual Preferences', + intensity: '⚡ Intensity Levels', + captionTone: '💬 Caption Tone', + audioPreferences: '🔊 Audio Preferences', + sessionDuration: '⏱️ Session Duration', + featurePreferences: '🎮 Feature Preferences', + boundaries: '🛡️ Boundaries' + }; + return names[category] || category; + } + + /** + * Build category editor HTML + * @param {string} category - Category name + * @param {Object} prefs - Preferences object + * @returns {string} Editor HTML + */ + buildCategoryEditor(category, prefs) { + if (category === 'intensity') { + return this.buildIntensitySliders(prefs); + } else if (category === 'sessionDuration') { + return this.buildDurationSelector(prefs); + } else { + return this.buildCheckboxes(category, prefs); + } + } + + /** + * Build intensity sliders + * @param {Object} prefs - Intensity preferences + * @returns {string} HTML + */ + buildIntensitySliders(prefs) { + let html = ''; + for (const [key, value] of Object.entries(prefs)) { + html += ` +
+ + +
+ `; + } + return html; + } + + /** + * Build duration selector + * @param {Object} prefs - Duration preferences + * @returns {string} HTML + */ + buildDurationSelector(prefs) { + const options = ['short', 'medium', 'long', 'marathon']; + let html = ''; + return html; + } + + /** + * Build checkboxes for category + * @param {string} category - Category name + * @param {Object} prefs - Preferences object + * @returns {string} HTML + */ + buildCheckboxes(category, prefs) { + let html = '
'; + for (const [key, value] of Object.entries(prefs)) { + if (value !== null) { // Skip undiscovered features + html += ` + + `; + } + } + html += '
'; + return html; + } + + /** + * Populate library manager + */ + populateLibraryManager() { + const container = document.getElementById('library-manager'); + if (!container) return; + + // Sync with existing library first + const syncResult = window.libraryManager.syncWithExistingLibrary(); + const stats = window.libraryManager.getLibraryStats(); + + container.innerHTML = ` +
+

📊 Library Statistics

+
+
+ Total Videos + ${stats.totalItems} +
+
+ Tagged + ${stats.taggedItems} +
+
+ Avg Rating + ${stats.averageRating}⭐ +
+
+ Favorites + ${stats.totalFavorites} +
+
+

+ 💡 Your existing video library (${syncResult.total} videos) is automatically imported. + You can add tags and ratings to organize your content. +

+

+ 📚 Manage your full library from the main menu Library tab for more detailed controls. +

+
+ `; + } + + /** + * Save checkpoint preferences and start level + * @param {number} levelNum - Level to start + */ + saveCheckpointAndStart(levelNum) { + console.log('💾 Saving checkpoint preferences...'); + + // Collect all preference changes + const updates = {}; + + // Get all checkboxes + document.querySelectorAll('input[type="checkbox"][data-category]').forEach(checkbox => { + const category = checkbox.dataset.category; + const key = checkbox.dataset.key; + + if (!updates[category]) updates[category] = {}; + updates[category][key] = checkbox.checked; + }); + + // Get all sliders + document.querySelectorAll('input[type="range"][data-category]').forEach(slider => { + const category = slider.dataset.category; + const key = slider.dataset.key; + + if (!updates[category]) updates[category] = {}; + updates[category][key] = parseInt(slider.value); + }); + + // Get all selects + document.querySelectorAll('select[data-category]').forEach(select => { + const category = select.dataset.category; + const key = select.dataset.key; + + if (!updates[category]) updates[category] = {}; + updates[category][key] = select.value; + }); + + // Save to preferenceManager + let saved = true; + if (Object.keys(updates).length > 0) { + saved = window.preferenceManager.updateMultipleCategories(updates, levelNum); + if (saved) { + console.log('✅ Preferences updated:', updates); + } else { + console.error('❌ Failed to save preferences'); + alert('⚠️ Unable to save preferences. Storage may be full.\n\nPlease restart the app and try again.'); + return; + } + } + + // Close modal and begin level + this.closeCheckpointModal(); + this.beginLevel(levelNum); + } + + /** + * Close checkpoint modal + */ + closeCheckpointModal() { + if (this.currentModal) { + this.currentModal.remove(); + this.currentModal = null; + } + } + + /** + * Begin level (after checkpoint or directly) + * @param {number} levelNum - Level to start + */ + beginLevel(levelNum) { + console.log(`🚀 Beginning Level ${levelNum}...`); + + // Use campaignManager to start level + const levelConfig = window.campaignManager.startLevel(levelNum); + + if (!levelConfig) { + alert('Unable to start this level. Please check requirements.'); + return; + } + + // Hide level select screen + const setupContainer = document.getElementById('academy-setup'); + if (setupContainer) { + setupContainer.style.display = 'none'; + } + + // Start the actual training session + // This would integrate with existing training-academy.html session logic + this.startTrainingSession(levelConfig); + } + + /** + * Start training session with level config + * @param {Object} levelConfig - Level configuration + */ + startTrainingSession(levelConfig) { + console.log('🎓 Starting training session with config:', levelConfig); + + // Get detailed level configuration from academyLevelData + const detailedConfig = window.academyLevelData.getLevelConfig(levelConfig.levelNumber); + if (!detailedConfig) { + console.error('⚠️ No level data found for level:', levelConfig.levelNumber); + return; + } + + console.log('📊 Detailed level config:', detailedConfig); + + // Get content filter based on user preferences + const preferenceFilter = window.preferenceManager.getContentFilter(); + + // Sync with existing library to ensure we have latest videos + window.libraryManager.syncWithExistingLibrary(); + + // Get media requirements for this level + const mediaRequirements = window.academyLevelData.getMediaForLevel( + levelConfig.levelNumber, + window.preferenceManager.getPreferences() + ); + + console.log('🎬 Media requirements:', mediaRequirements); + + // Get filtered media from library + const mediaItems = window.libraryManager.getMediaForPreferences( + mediaRequirements.videoFilter, + mediaRequirements.videoCount + ); + + console.log('🎬 Loaded media for session:', mediaItems.length, 'items'); + console.log('🎯 Preference filter:', preferenceFilter); + console.log('⏱️ Session duration:', detailedConfig.session.duration); + console.log('📋 Tasks:', detailedConfig.tasks.length); + console.log('🎯 Objectives:', detailedConfig.objectives); + + // If we have media items, log their details + if (mediaItems.length > 0) { + console.log('📹 Sample media item:', mediaItems[0]); + } else { + console.warn('⚠️ No media items matched preferences. Will use all available videos.'); + // Fallback to all videos if no matches + const allVideos = window.libraryManager.getAllVideosWithMetadata(); + console.log('📹 Using all videos as fallback:', allVideos.length); + } + + // TODO: Integrate with existing startTrainingSession() in training-academy.html + // For now, just call the existing function if available + if (typeof window.startTrainingSession === 'function') { + window.startTrainingSession(); + } else { + console.error('⚠️ startTrainingSession() not found in window scope'); + } + } +} + +// Create global instance +window.academyUI = new AcademyUI(); diff --git a/src/features/academy/campaignManager.js b/src/features/academy/campaignManager.js new file mode 100644 index 0000000..16c34e2 --- /dev/null +++ b/src/features/academy/campaignManager.js @@ -0,0 +1,290 @@ +/** + * Campaign Manager + * Handles The Academy's 30-level campaign progression system + */ + +class CampaignManager { + constructor() { + this.initializeProgress(); + } + + /** + * Initialize academy progress if it doesn't exist + */ + initializeProgress() { + // gameData is available globally via window.gameData + if (!window.gameData.academyProgress) { + window.gameData.academyProgress = { + version: 1, + currentLevel: 1, + highestUnlockedLevel: 1, + completedLevels: [], + currentArc: 'Foundation', + failedAttempts: {}, + totalSessionTime: 0, + lastPlayedLevel: null, + lastPlayedDate: null, + graduationCompleted: false, + freeplayUnlocked: false, + ascendedModeUnlocked: false, + selectedPath: null, + featuresUnlocked: [] + }; + this.saveProgress(); + } + } + + /** + * Save progress to localStorage + */ + saveProgress() { + localStorage.setItem('webGame-data', JSON.stringify(window.gameData)); + } + + /** + * Get list of unlocked levels + * @returns {Array} Array of unlocked level numbers + */ + getUnlockedLevels() { + const unlocked = []; + const highest = window.gameData.academyProgress.highestUnlockedLevel; + for (let i = 1; i <= highest; i++) { + unlocked.push(i); + } + return unlocked; + } + + /** + * Check if a level is unlocked + * @param {number} levelNum - Level number to check + * @returns {boolean} + */ + isLevelUnlocked(levelNum) { + return levelNum <= window.gameData.academyProgress.highestUnlockedLevel; + } + + /** + * Check if a level is completed + * @param {number} levelNum - Level number to check + * @returns {boolean} + */ + isLevelCompleted(levelNum) { + return window.gameData.academyProgress.completedLevels.includes(levelNum); + } + + /** + * Start a level + * @param {number} levelNum - Level number to start + * @returns {Object|null} Level config or null if invalid + */ + startLevel(levelNum) { + // Validate level is unlocked + if (!this.isLevelUnlocked(levelNum)) { + console.error(`Level ${levelNum} is locked. Complete previous levels first.`); + return null; + } + + // Update current level + window.gameData.academyProgress.currentLevel = levelNum; + window.gameData.academyProgress.lastPlayedLevel = levelNum; + window.gameData.academyProgress.lastPlayedDate = new Date().toISOString(); + + // Update current arc + window.gameData.academyProgress.currentArc = this.getArcForLevel(levelNum); + + this.saveProgress(); + + console.log(`Started Level ${levelNum} (${gameData.academyProgress.currentArc} Arc)`); + + return { + levelNum, + arc: window.gameData.academyProgress.currentArc, + isCheckpoint: this.isCheckpointLevel(levelNum) + }; + } + + /** + * Complete a level + * @param {number} levelNum - Level number completed + * @param {Object} sessionData - Data from the session + * @returns {Object} Completion results + */ + completeLevel(levelNum, sessionData = {}) { + const progress = window.gameData.academyProgress; + + // Add to completed levels if not already there + if (!progress.completedLevels.includes(levelNum)) { + progress.completedLevels.push(levelNum); + } + + // Unlock next level + const nextLevel = levelNum + 1; + let nextLevelUnlocked = false; + if (nextLevel <= 30 && nextLevel > progress.highestUnlockedLevel) { + progress.highestUnlockedLevel = nextLevel; + nextLevelUnlocked = true; + console.log(`🔓 Level ${nextLevel} unlocked!`); + } + + // Update session time + if (sessionData.duration) { + progress.totalSessionTime += sessionData.duration; + } + + // Check for arc completion + const arcComplete = this.checkArcCompletion(levelNum); + + // Reset consecutive failures on success + progress.consecutiveLevelsWithoutFailure = + (progress.consecutiveLevelsWithoutFailure || 0) + 1; + + this.saveProgress(); + + console.log(`✅ Level ${levelNum} completed!`); + + return { + levelCompleted: levelNum, + nextLevelUnlocked, + nextLevel: nextLevelUnlocked ? nextLevel : null, + arcComplete, + completedArc: arcComplete ? this.getArcForLevel(levelNum) : null + }; + } + + /** + * Fail a level + * @param {number} levelNum - Level that was failed + * @param {string} reason - Failure reason ('cumming', 'abandoned', 'feature-closed') + */ + failLevel(levelNum, reason) { + const progress = window.gameData.academyProgress; + + // Increment failed attempts for this level + if (!progress.failedAttempts[levelNum]) { + progress.failedAttempts[levelNum] = 0; + } + progress.failedAttempts[levelNum]++; + + // Track total failures + if (!progress.totalFailedAttempts) { + progress.totalFailedAttempts = 0; + } + progress.totalFailedAttempts++; + + // Track failure by reason + if (!progress.failuresByReason) { + progress.failuresByReason = { + cumming: 0, + abandoned: 0, + featureClosed: 0 + }; + } + if (progress.failuresByReason[reason] !== undefined) { + progress.failuresByReason[reason]++; + } + + // Reset consecutive success streak + progress.consecutiveLevelsWithoutFailure = 0; + + this.saveProgress(); + + console.log(`❌ Level ${levelNum} failed (${reason}). Attempts: ${progress.failedAttempts[levelNum]}`); + } + + /** + * Get the arc name for a level + * @param {number} levelNum - Level number + * @returns {string} Arc name + */ + getArcForLevel(levelNum) { + if (levelNum >= 1 && levelNum <= 5) return 'Foundation'; + if (levelNum >= 6 && levelNum <= 10) return 'Feature Discovery'; + if (levelNum >= 11 && levelNum <= 15) return 'Mind & Body'; + if (levelNum >= 16 && levelNum <= 20) return 'Advanced Training'; + if (levelNum >= 21 && levelNum <= 25) return 'Path Specialization'; + if (levelNum >= 26 && levelNum <= 30) return 'Ultimate Mastery'; + return 'Unknown'; + } + + /** + * Get current arc + * @returns {string} Current arc name + */ + getCurrentArc() { + return window.gameData.academyProgress.currentArc; + } + + /** + * Check if level is a checkpoint (1, 5, 10, 15, 20, 25) + * @param {number} levelNum - Level number + * @returns {boolean} + */ + isCheckpointLevel(levelNum) { + return [1, 5, 10, 15, 20, 25].includes(levelNum); + } + + /** + * Check if an arc is complete + * @param {number} levelNum - Level just completed + * @returns {boolean} + */ + checkArcCompletion(levelNum) { + const arcEndLevels = [5, 10, 15, 20, 25, 30]; + return arcEndLevels.includes(levelNum); + } + + /** + * Get progress statistics + * @returns {Object} Progress stats + */ + getProgressStats() { + const progress = window.gameData.academyProgress; + return { + currentLevel: progress.currentLevel, + highestUnlockedLevel: progress.highestUnlockedLevel, + completedLevels: progress.completedLevels.length, + totalLevels: 30, + percentComplete: (progress.completedLevels.length / 30) * 100, + currentArc: progress.currentArc, + totalSessionTime: progress.totalSessionTime, + failedAttempts: Object.values(progress.failedAttempts).reduce((a, b) => a + b, 0), + consecutiveSuccesses: progress.consecutiveLevelsWithoutFailure || 0 + }; + } + + /** + * Reset progress (for testing or fresh start) + */ + resetProgress() { + window.gameData.academyProgress = { + version: 1, + currentLevel: 1, + highestUnlockedLevel: 1, + completedLevels: [], + currentArc: 'Foundation', + failedAttempts: {}, + totalSessionTime: 0, + lastPlayedLevel: null, + lastPlayedDate: null, + graduationCompleted: false, + freeplayUnlocked: false, + ascendedModeUnlocked: false, + selectedPath: null, + featuresUnlocked: [], + totalFailedAttempts: 0, + failuresByReason: { + cumming: 0, + abandoned: 0, + featureClosed: 0 + }, + consecutiveLevelsWithoutFailure: 0 + }; + this.saveProgress(); + console.log('🔄 Academy progress reset'); + } +} + +// Create singleton instance and expose globally +window.campaignManager = new CampaignManager(); + +console.log('🎓 Campaign Manager initialized'); diff --git a/src/features/academy/libraryManager.js b/src/features/academy/libraryManager.js new file mode 100644 index 0000000..1902567 --- /dev/null +++ b/src/features/academy/libraryManager.js @@ -0,0 +1,710 @@ +/** + * Library Management System for The Academy + * Handles media tagging, organization, quality ratings, and preference-based filtering + */ + +class LibraryManager { + constructor() { + this.initializeLibrary(); + } + + /** + * Initialize library structure in gameData if it doesn't exist + * Integrates with existing desktopFileManager video/photo system + */ + initializeLibrary() { + if (!window.gameData.academyLibrary) { + window.gameData.academyLibrary = { + version: 1, + lastUpdated: new Date().toISOString(), + + // Media items with tags and metadata + // Keys are file paths from desktopFileManager.getAllVideos() + media: { + // Key: file path from existing library, Value: metadata object + // Example: "C:/Users/drew/Videos/video1.mp4": { tags: [...], rating: 5, ... } + }, + + // Tag definitions and usage counts + tags: { + // Content theme tags + contentThemes: ['dominance', 'submission', 'humiliation', 'worship', 'edging', 'denial', + 'cei', 'sissy', 'bbc', 'feet', 'femdom', 'maledom', 'lesbian', 'gay', + 'trans', 'hentai', 'pov', 'joi', 'gooning', 'mindbreak'], + + // Visual style tags + visualStyles: ['solo', 'couples', 'group', 'amateur', 'professional', 'animated', + 'real', 'closeup', 'fullbody', 'pov', 'compilation', 'pmv', 'slowmo', + 'artistic', 'raw'], + + // Intensity tags + intensity: ['soft', 'moderate', 'intense', 'extreme', 'hardcore', 'gentle', 'rough'], + + // Audio tags + audio: ['music', 'talking', 'moaning', 'silent', 'asmr', 'binaural', 'soundfx', + 'voiceover', 'ambient'], + + // Quality tags + quality: ['lowres', 'sd', 'hd', '720p', '1080p', '4k', 'vr'], + + // Duration tags + duration: ['short', 'medium', 'long', 'loop', 'extended'], + + // Actor/performer tags (will be populated dynamically) + performers: [], + + // Custom user tags + custom: [] + }, + + // Tag usage statistics + tagStats: { + // Tag name -> count of media items with that tag + }, + + // Quality ratings by user + ratings: { + // File path -> rating (1-5 stars) + }, + + // User's favorite/disliked items + favorites: [], + disliked: [], + + // Collection system (playlists/categories) + collections: { + // Collection name -> array of file paths + }, + + // Scan history (track what's been tagged) + scanHistory: { + lastFullScan: null, + scannedFolders: [], + totalItemsScanned: 0, + totalItemsTagged: 0 + } + }; + + this.saveLibrary(); + } + } + + /** + * Get the full library object + * @returns {Object} Library object + */ + getLibrary() { + return window.gameData.academyLibrary; + } + + /** + * Add or update media item with tags and metadata + * @param {string} filePath - Path to media file + * @param {Object} metadata - Metadata object { tags, rating, duration, etc. } + * @returns {boolean} Success status + */ + addMediaItem(filePath, metadata = {}) { + const library = this.getLibrary(); + + // Create or update media item + if (!library.media[filePath]) { + library.media[filePath] = { + filePath: filePath, + tags: [], + rating: 0, + timesPlayed: 0, + lastPlayed: null, + addedDate: new Date().toISOString(), + duration: null, + fileSize: null, + format: this.getFileFormat(filePath) + }; + } + + // Merge metadata + Object.assign(library.media[filePath], metadata); + + // Update tag statistics + if (metadata.tags) { + this.updateTagStats(metadata.tags); + } + + library.lastUpdated = new Date().toISOString(); + this.saveLibrary(); + return true; + } + + /** + * Add tags to a media item + * @param {string} filePath - Path to media file + * @param {Array} tags - Array of tag names + * @returns {boolean} Success status + */ + addTags(filePath, tags) { + const library = this.getLibrary(); + + if (!library.media[filePath]) { + this.addMediaItem(filePath); + } + + const item = library.media[filePath]; + + // Add new tags (avoid duplicates) + tags.forEach(tag => { + if (!item.tags.includes(tag)) { + item.tags.push(tag); + } + }); + + // Update tag statistics + this.updateTagStats(tags); + + library.lastUpdated = new Date().toISOString(); + this.saveLibrary(); + return true; + } + + /** + * Remove tags from a media item + * @param {string} filePath - Path to media file + * @param {Array} tags - Array of tag names to remove + * @returns {boolean} Success status + */ + removeTags(filePath, tags) { + const library = this.getLibrary(); + + if (!library.media[filePath]) { + return false; + } + + const item = library.media[filePath]; + + tags.forEach(tag => { + const index = item.tags.indexOf(tag); + if (index > -1) { + item.tags.splice(index, 1); + + // Decrement tag stat + if (library.tagStats[tag]) { + library.tagStats[tag] = Math.max(0, library.tagStats[tag] - 1); + } + } + }); + + library.lastUpdated = new Date().toISOString(); + this.saveLibrary(); + return true; + } + + /** + * Bulk tag multiple files at once + * @param {Array} filePaths - Array of file paths + * @param {Array} tags - Array of tags to add to all files + * @returns {Object} Result object with success count + */ + bulkAddTags(filePaths, tags) { + let successCount = 0; + + filePaths.forEach(filePath => { + if (this.addTags(filePath, tags)) { + successCount++; + } + }); + + return { + success: true, + filesTagged: successCount, + totalFiles: filePaths.length, + tags: tags + }; + } + + /** + * Set quality rating for a media item + * @param {string} filePath - Path to media file + * @param {number} rating - Rating (1-5) + * @returns {boolean} Success status + */ + setRating(filePath, rating) { + if (rating < 1 || rating > 5) { + console.error('Rating must be between 1 and 5'); + return false; + } + + const library = this.getLibrary(); + + if (!library.media[filePath]) { + this.addMediaItem(filePath); + } + + library.media[filePath].rating = rating; + library.ratings[filePath] = rating; + + library.lastUpdated = new Date().toISOString(); + this.saveLibrary(); + return true; + } + + /** + * Add media item to favorites + * @param {string} filePath - Path to media file + * @returns {boolean} Success status + */ + addToFavorites(filePath) { + const library = this.getLibrary(); + + if (!library.favorites.includes(filePath)) { + library.favorites.push(filePath); + + // Remove from disliked if present + const dislikedIndex = library.disliked.indexOf(filePath); + if (dislikedIndex > -1) { + library.disliked.splice(dislikedIndex, 1); + } + + library.lastUpdated = new Date().toISOString(); + this.saveLibrary(); + } + + return true; + } + + /** + * Add media item to disliked list + * @param {string} filePath - Path to media file + * @returns {boolean} Success status + */ + addToDisliked(filePath) { + const library = this.getLibrary(); + + if (!library.disliked.includes(filePath)) { + library.disliked.push(filePath); + + // Remove from favorites if present + const favIndex = library.favorites.indexOf(filePath); + if (favIndex > -1) { + library.favorites.splice(favIndex, 1); + } + + library.lastUpdated = new Date().toISOString(); + this.saveLibrary(); + } + + return true; + } + + /** + * Search/filter media by tags and criteria + * @param {Object} filters - Filter configuration + * @returns {Array} Array of matching media items + */ + searchMedia(filters = {}) { + const library = this.getLibrary(); + let results = Object.values(library.media); + + // Filter by required tags (item must have ALL these tags) + if (filters.requiredTags && filters.requiredTags.length > 0) { + results = results.filter(item => + filters.requiredTags.every(tag => item.tags.includes(tag)) + ); + } + + // Filter by any tags (item must have AT LEAST ONE of these tags) + if (filters.anyTags && filters.anyTags.length > 0) { + results = results.filter(item => + filters.anyTags.some(tag => item.tags.includes(tag)) + ); + } + + // Filter by excluded tags (item must NOT have any of these tags) + if (filters.excludedTags && filters.excludedTags.length > 0) { + results = results.filter(item => + !filters.excludedTags.some(tag => item.tags.includes(tag)) + ); + } + + // Filter by minimum rating + if (filters.minRating) { + results = results.filter(item => item.rating >= filters.minRating); + } + + // Filter by favorites only + if (filters.favoritesOnly) { + results = results.filter(item => library.favorites.includes(item.filePath)); + } + + // Exclude disliked + if (filters.excludeDisliked) { + results = results.filter(item => !library.disliked.includes(item.filePath)); + } + + // Filter by format + if (filters.format) { + results = results.filter(item => item.format === filters.format); + } + + // Sort results + if (filters.sortBy) { + results = this.sortResults(results, filters.sortBy, filters.sortOrder || 'desc'); + } + + // Limit results + if (filters.limit) { + results = results.slice(0, filters.limit); + } + + return results; + } + + /** + * Get media items matching user's preferences (from preferenceManager) + * @param {Object} preferenceFilter - Filter from preferenceManager.getContentFilter() + * @param {number} limit - Maximum number of items to return + * @returns {Array} Array of matching media items + */ + getMediaForPreferences(preferenceFilter, limit = 10) { + const filters = { + anyTags: [ + ...preferenceFilter.themes, + ...preferenceFilter.visuals, + ...preferenceFilter.audio, + ...preferenceFilter.tones + ], + excludedTags: [ + ...preferenceFilter.exclude.hardLimits, + ...preferenceFilter.exclude.softLimits + ], + excludeDisliked: true, + sortBy: 'rating', + sortOrder: 'desc', + limit: limit + }; + + return this.searchMedia(filters); + } + + /** + * Create a collection (playlist/category) + * @param {string} name - Collection name + * @param {Array} filePaths - Array of file paths + * @returns {boolean} Success status + */ + createCollection(name, filePaths = []) { + const library = this.getLibrary(); + + library.collections[name] = filePaths; + + library.lastUpdated = new Date().toISOString(); + this.saveLibrary(); + return true; + } + + /** + * Add items to a collection + * @param {string} collectionName - Collection name + * @param {Array} filePaths - File paths to add + * @returns {boolean} Success status + */ + addToCollection(collectionName, filePaths) { + const library = this.getLibrary(); + + if (!library.collections[collectionName]) { + this.createCollection(collectionName, filePaths); + } else { + filePaths.forEach(filePath => { + if (!library.collections[collectionName].includes(filePath)) { + library.collections[collectionName].push(filePath); + } + }); + } + + library.lastUpdated = new Date().toISOString(); + this.saveLibrary(); + return true; + } + + /** + * Get all items in a collection + * @param {string} collectionName - Collection name + * @returns {Array} Array of media items + */ + getCollection(collectionName) { + const library = this.getLibrary(); + + if (!library.collections[collectionName]) { + return []; + } + + return library.collections[collectionName].map(filePath => + library.media[filePath] + ).filter(item => item !== undefined); + } + + /** + * Get library statistics + * @returns {Object} Stats object + */ + getLibraryStats() { + const library = this.getLibrary(); + + const totalItems = Object.keys(library.media).length; + const taggedItems = Object.values(library.media).filter(item => item.tags.length > 0).length; + const ratedItems = Object.values(library.media).filter(item => item.rating > 0).length; + + // Calculate average rating + const ratings = Object.values(library.media).map(item => item.rating).filter(r => r > 0); + const avgRating = ratings.length > 0 ? (ratings.reduce((a, b) => a + b, 0) / ratings.length).toFixed(2) : 0; + + return { + totalItems: totalItems, + taggedItems: taggedItems, + untaggedItems: totalItems - taggedItems, + ratedItems: ratedItems, + averageRating: parseFloat(avgRating), + totalFavorites: library.favorites.length, + totalDisliked: library.disliked.length, + totalCollections: Object.keys(library.collections).length, + totalTags: Object.keys(library.tagStats).length, + mostUsedTags: this.getMostUsedTags(5), + lastUpdated: library.lastUpdated, + scanHistory: library.scanHistory + }; + } + + /** + * Get most used tags + * @param {number} limit - Number of tags to return + * @returns {Array} Array of {tag, count} objects + */ + getMostUsedTags(limit = 10) { + const library = this.getLibrary(); + + return Object.entries(library.tagStats) + .sort((a, b) => b[1] - a[1]) + .slice(0, limit) + .map(([tag, count]) => ({ tag, count })); + } + + /** + * Get all available tags by category + * @returns {Object} Tags organized by category + */ + getAllTags() { + return this.getLibrary().tags; + } + + /** + * Sync with existing video library from desktopFileManager + * Imports videos from existing library and preserves existing Academy tags/ratings + */ + syncWithExistingLibrary() { + console.log('🔄 Syncing with existing video library...'); + + let allVideos = []; + + // Get videos from desktopFileManager (primary source) + if (window.desktopFileManager && typeof window.desktopFileManager.getAllVideos === 'function') { + allVideos = window.desktopFileManager.getAllVideos(); + console.log(`📹 Found ${allVideos.length} videos from desktopFileManager`); + } + + // Fallback to unifiedVideoLibrary in localStorage + if (allVideos.length === 0) { + const unifiedData = JSON.parse(localStorage.getItem('unifiedVideoLibrary') || '{}'); + allVideos = unifiedData.allVideos || []; + console.log(`📹 Found ${allVideos.length} videos from unifiedVideoLibrary`); + } + + // Import videos into Academy library while preserving existing Academy metadata + const library = this.getLibrary(); + let newCount = 0; + let existingCount = 0; + + allVideos.forEach(video => { + const filePath = video.path || video.name; + + if (!library.media[filePath]) { + // New video - add with minimal metadata + library.media[filePath] = { + filePath: filePath, + name: video.name, + tags: [], + rating: 0, + timesPlayed: 0, + lastPlayed: null, + addedDate: new Date().toISOString(), + duration: video.duration || null, + fileSize: video.size || null, + format: video.format || this.getFileFormat(filePath), + // Preserve original library metadata + originalSource: video.directory || video.source || 'Unknown', + resolution: video.resolution || null, + thumbnail: video.thumbnail || null + }; + newCount++; + } else { + // Existing video - update non-Academy fields only + library.media[filePath].name = video.name; + library.media[filePath].duration = video.duration || library.media[filePath].duration; + library.media[filePath].fileSize = video.size || library.media[filePath].fileSize; + library.media[filePath].format = video.format || library.media[filePath].format; + library.media[filePath].resolution = video.resolution || library.media[filePath].resolution; + library.media[filePath].thumbnail = video.thumbnail || library.media[filePath].thumbnail; + existingCount++; + } + }); + + library.lastUpdated = new Date().toISOString(); + library.scanHistory.lastFullScan = new Date().toISOString(); + library.scanHistory.totalItemsScanned = allVideos.length; + library.scanHistory.totalItemsTagged = Object.values(library.media).filter(item => item.tags.length > 0).length; + + this.saveLibrary(); + + console.log(`✅ Sync complete: ${newCount} new, ${existingCount} existing, ${allVideos.length} total videos`); + + return { + total: allVideos.length, + new: newCount, + existing: existingCount + }; + } + + /** + * Get all videos from existing library (convenience method) + * @returns {Array} Array of video objects with Academy metadata + */ + getAllVideosWithMetadata() { + const library = this.getLibrary(); + return Object.values(library.media); + } + + /** + * Get video by file path + * @param {string} filePath - Path to video file + * @returns {Object|null} Video object with metadata + */ + getVideoByPath(filePath) { + const library = this.getLibrary(); + return library.media[filePath] || null; + } + + /** + * Add a custom tag + * @param {string} tagName - Custom tag name + * @returns {boolean} Success status + */ + addCustomTag(tagName) { + const library = this.getLibrary(); + + if (!library.tags.custom.includes(tagName)) { + library.tags.custom.push(tagName); + library.lastUpdated = new Date().toISOString(); + this.saveLibrary(); + } + + return true; + } + + /** + * Record that a media item was played + * @param {string} filePath - Path to media file + * @returns {boolean} Success status + */ + recordPlay(filePath) { + const library = this.getLibrary(); + + if (!library.media[filePath]) { + this.addMediaItem(filePath); + } + + library.media[filePath].timesPlayed = (library.media[filePath].timesPlayed || 0) + 1; + library.media[filePath].lastPlayed = new Date().toISOString(); + + this.saveLibrary(); + return true; + } + + /** + * Get recently played items + * @param {number} limit - Number of items to return + * @returns {Array} Array of media items + */ + getRecentlyPlayed(limit = 10) { + const library = this.getLibrary(); + + return Object.values(library.media) + .filter(item => item.lastPlayed !== null) + .sort((a, b) => new Date(b.lastPlayed) - new Date(a.lastPlayed)) + .slice(0, limit); + } + + /** + * Reset library to empty state + * @returns {boolean} Success status + */ + resetLibrary() { + delete window.gameData.academyLibrary; + this.initializeLibrary(); + return true; + } + + // Helper methods + + /** + * Update tag statistics + * @param {Array} tags - Tags to increment + */ + updateTagStats(tags) { + const library = this.getLibrary(); + + tags.forEach(tag => { + library.tagStats[tag] = (library.tagStats[tag] || 0) + 1; + }); + } + + /** + * Get file format from path + * @param {string} filePath - File path + * @returns {string} File format (mp4, webm, etc.) + */ + getFileFormat(filePath) { + const ext = filePath.split('.').pop().toLowerCase(); + return ext; + } + + /** + * Sort results by field + * @param {Array} results - Results to sort + * @param {string} field - Field to sort by + * @param {string} order - 'asc' or 'desc' + * @returns {Array} Sorted results + */ + sortResults(results, field, order = 'desc') { + return results.sort((a, b) => { + if (field === 'rating' || field === 'timesPlayed') { + return order === 'desc' ? b[field] - a[field] : a[field] - b[field]; + } else if (field === 'lastPlayed' || field === 'addedDate') { + const dateA = new Date(a[field]); + const dateB = new Date(b[field]); + return order === 'desc' ? dateB - dateA : dateA - dateB; + } else { + return 0; + } + }); + } + + /** + * Save library to localStorage + */ + saveLibrary() { + try { + localStorage.setItem('webGame-data', JSON.stringify(window.gameData)); + } catch (error) { + console.error('Failed to save library:', error); + } + } +} + +// Create global instance +window.libraryManager = new LibraryManager(); diff --git a/src/features/academy/preferenceManager.js b/src/features/academy/preferenceManager.js new file mode 100644 index 0000000..cdfa8a4 --- /dev/null +++ b/src/features/academy/preferenceManager.js @@ -0,0 +1,482 @@ +/** + * Preference Management System for The Academy + * Handles user preferences across 8 categories, checkpoint modals, and preference-based filtering + */ + +class PreferenceManager { + constructor() { + this.initializePreferences(); + } + + /** + * Initialize preferences structure in gameData if it doesn't exist + */ + initializePreferences() { + if (!window.gameData.academyPreferences) { + window.gameData.academyPreferences = { + version: 1, + lastUpdated: new Date().toISOString(), + checkpointHistory: [], // Track when preferences were updated + + // Category 1: Content Themes (multi-select) + contentThemes: { + dominance: false, + submission: false, + humiliation: false, + worship: false, + edging: false, + denial: false, + cei: false, + sissy: false, + bbc: false, + feet: false, + femdom: false, + maledom: false, + lesbian: false, + gay: false, + trans: false, + hentai: false, + pov: false, + joi: false, + gooning: false, + mindbreak: false + }, + + // Category 2: Visual Preferences (multi-select) + visualPreferences: { + solo: false, + couples: false, + group: false, + amateur: false, + professional: false, + animated: false, + realPorn: false, + closeups: false, + fullBody: false, + pov: false, + compilation: false, + pmv: false, + slowmo: false, + artistic: false, + raw: false + }, + + // Category 3: Intensity Levels (slider 1-5) + intensity: { + visualIntensity: 3, // How explicit/hardcore + paceIntensity: 3, // How fast/aggressive + mentalIntensity: 3, // How mind-breaking + audioIntensity: 3, // How loud/overwhelming + taskDifficulty: 3 // How challenging + }, + + // Category 4: Caption/Text Tone (multi-select) + captionTone: { + encouraging: false, + mocking: false, + commanding: false, + seductive: false, + degrading: false, + playful: false, + serious: false, + casual: false, + formal: false, + extreme: false + }, + + // Category 5: Audio Preferences (multi-select) + audioPreferences: { + femaleVoice: false, + maleVoice: false, + moaning: false, + talking: false, + music: false, + ambience: false, + asmr: false, + binaural: false, + silence: false, + soundEffects: false + }, + + // Category 6: Session Duration (single-select) + sessionDuration: { + preferred: 'medium', // 'short' (5-15m), 'medium' (15-30m), 'long' (30-60m), 'marathon' (60m+) + allowFlexibility: true // Can go shorter/longer based on performance + }, + + // Category 7: Feature Preferences (multi-select - unlocks as features discovered) + featurePreferences: { + webcam: null, // null = not yet discovered, true/false after discovery + tts: null, + interactiveTasks: null, + edgingTimer: null, + denialLocks: null, + punishments: null, + rewards: null, + progressTracking: null, + mediaLibrary: null, + customPlaylists: null + }, + + // Category 8: Boundaries (multi-select for hard limits) + boundaries: { + hardLimits: [], // User-specified content to NEVER show + softLimits: [], // User-specified content to show sparingly + triggerWarnings: [], // User wants warnings before certain content + requireConfirmation: [] // User wants to confirm before certain tasks + } + }; + + this.savePreferences(); + } + } + + /** + * Get all current preferences + * @returns {Object} Full preferences object + */ + getPreferences() { + return window.gameData.academyPreferences; + } + + /** + * Get preferences for a specific category + * @param {string} category - Category name (contentThemes, visualPreferences, etc.) + * @returns {Object} Category preferences + */ + getCategoryPreferences(category) { + const prefs = this.getPreferences(); + return prefs[category] || null; + } + + /** + * Update preferences for a specific category + * @param {string} category - Category name + * @param {Object} updates - Object with preference updates + * @param {number} checkpointLevel - Level number where update occurred (optional) + * @returns {boolean} Success status + */ + updateCategoryPreferences(category, updates, checkpointLevel = null) { + const prefs = this.getPreferences(); + + if (!prefs[category]) { + console.error(`Invalid category: ${category}`); + return false; + } + + // Update the category + Object.assign(prefs[category], updates); + + // Update metadata + prefs.lastUpdated = new Date().toISOString(); + + // Track checkpoint history + if (checkpointLevel !== null) { + prefs.checkpointHistory.push({ + level: checkpointLevel, + category: category, + timestamp: new Date().toISOString(), + changes: updates + }); + } + + this.savePreferences(); + return true; + } + + /** + * Bulk update multiple categories at once (used at checkpoints) + * @param {Object} categoryUpdates - Object with category names as keys, updates as values + * @param {number} checkpointLevel - Level number where update occurred + * @returns {boolean} Success status + */ + updateMultipleCategories(categoryUpdates, checkpointLevel) { + const prefs = this.getPreferences(); + + for (const [category, updates] of Object.entries(categoryUpdates)) { + if (!prefs[category]) { + console.error(`Invalid category: ${category}`); + continue; + } + + Object.assign(prefs[category], updates); + } + + // Update metadata + prefs.lastUpdated = new Date().toISOString(); + + // Track checkpoint history + prefs.checkpointHistory.push({ + level: checkpointLevel, + categories: Object.keys(categoryUpdates), + timestamp: new Date().toISOString(), + changes: categoryUpdates + }); + + return this.savePreferences(); + } + + /** + * Get content filter based on current preferences + * Used to filter media library for level content selection + * @returns {Object} Filter configuration + */ + getContentFilter() { + const prefs = this.getPreferences(); + + return { + // Theme filters + themes: this.getActivePreferences(prefs.contentThemes), + + // Visual filters + visuals: this.getActivePreferences(prefs.visualPreferences), + + // Audio filters + audio: this.getActivePreferences(prefs.audioPreferences), + + // Tone filters + tones: this.getActivePreferences(prefs.captionTone), + + // Intensity filters + intensity: { + visual: prefs.intensity.visualIntensity, + pace: prefs.intensity.paceIntensity, + mental: prefs.intensity.mentalIntensity, + audio: prefs.intensity.audioIntensity, + difficulty: prefs.intensity.taskDifficulty + }, + + // Duration preference + duration: prefs.sessionDuration.preferred, + allowFlexibility: prefs.sessionDuration.allowFlexibility, + + // Boundaries (exclude these) + exclude: { + hardLimits: prefs.boundaries.hardLimits, + softLimits: prefs.boundaries.softLimits + }, + + // Warnings needed + warnings: prefs.boundaries.triggerWarnings, + + // Confirmation required + confirmations: prefs.boundaries.requireConfirmation + }; + } + + /** + * Get list of active (true) preferences from a category object + * @param {Object} categoryPrefs - Category preferences object + * @returns {Array} Array of active preference names + */ + getActivePreferences(categoryPrefs) { + return Object.entries(categoryPrefs) + .filter(([key, value]) => value === true) + .map(([key]) => key); + } + + /** + * Check if a checkpoint level should show preference modal + * @param {number} levelNum - Level number + * @returns {boolean} True if checkpoint level + */ + isCheckpointLevel(levelNum) { + return [1, 5, 10, 15, 20, 25].includes(levelNum); + } + + /** + * Get checkpoint modal configuration for a specific level + * @param {number} levelNum - Level number + * @returns {Object} Modal configuration with categories to show + */ + getCheckpointModalConfig(levelNum) { + const configs = { + 1: { + title: "Welcome to The Academy", + description: "Let's set up your initial preferences. You can always change these later at checkpoints (L5, 10, 15, 20, 25).", + categories: ['contentThemes', 'visualPreferences', 'sessionDuration'], + isInitial: true + }, + 5: { + title: "Checkpoint: Refine Your Experience", + description: "You've completed the Foundation arc. Let's refine your preferences based on what you've experienced.", + categories: ['contentThemes', 'visualPreferences', 'intensity', 'captionTone'], + isInitial: false + }, + 10: { + title: "Checkpoint: Feature Discovery Complete", + description: "Now that you've explored all features, let's optimize your sessions.", + categories: ['featurePreferences', 'audioPreferences', 'intensity', 'sessionDuration'], + isInitial: false + }, + 15: { + title: "Checkpoint: Deepening Your Training", + description: "You're halfway through. Time to deepen your preferences.", + categories: ['contentThemes', 'captionTone', 'intensity', 'boundaries'], + isInitial: false + }, + 20: { + title: "Checkpoint: Advanced Personalization", + description: "You're in the Mastery arc. Let's perfect your experience.", + categories: ['visualPreferences', 'audioPreferences', 'featurePreferences', 'intensity'], + isInitial: false + }, + 25: { + title: "Checkpoint: Final Refinement", + description: "Almost at graduation. Final chance to perfect your preferences.", + categories: ['contentThemes', 'visualPreferences', 'intensity', 'captionTone', 'boundaries'], + isInitial: false + } + }; + + return configs[levelNum] || null; + } + + /** + * Get checkpoint history + * @returns {Array} Array of checkpoint update records + */ + getCheckpointHistory() { + return this.getPreferences().checkpointHistory || []; + } + + /** + * Mark a feature as discovered (unlocks it in featurePreferences) + * @param {string} featureName - Feature name (webcam, tts, etc.) + * @returns {boolean} Success status + */ + discoverFeature(featureName) { + const prefs = this.getPreferences(); + + if (!prefs.featurePreferences.hasOwnProperty(featureName)) { + console.error(`Invalid feature: ${featureName}`); + return false; + } + + // Set to false initially (discovered but not enabled) + // User will choose at next checkpoint + if (prefs.featurePreferences[featureName] === null) { + prefs.featurePreferences[featureName] = false; + prefs.lastUpdated = new Date().toISOString(); + this.savePreferences(); + } + + return true; + } + + /** + * Get list of discovered features + * @returns {Array} Array of discovered feature names + */ + getDiscoveredFeatures() { + const prefs = this.getPreferences(); + return Object.entries(prefs.featurePreferences) + .filter(([key, value]) => value !== null) + .map(([key]) => key); + } + + /** + * Get list of enabled features + * @returns {Array} Array of enabled feature names + */ + getEnabledFeatures() { + const prefs = this.getPreferences(); + return Object.entries(prefs.featurePreferences) + .filter(([key, value]) => value === true) + .map(([key]) => key); + } + + /** + * Add a hard limit (content to never show) + * @param {string} limitTag - Tag to add to hard limits + * @returns {boolean} Success status + */ + addHardLimit(limitTag) { + const prefs = this.getPreferences(); + if (!prefs.boundaries.hardLimits.includes(limitTag)) { + prefs.boundaries.hardLimits.push(limitTag); + prefs.lastUpdated = new Date().toISOString(); + this.savePreferences(); + } + return true; + } + + /** + * Remove a hard limit + * @param {string} limitTag - Tag to remove from hard limits + * @returns {boolean} Success status + */ + removeHardLimit(limitTag) { + const prefs = this.getPreferences(); + const index = prefs.boundaries.hardLimits.indexOf(limitTag); + if (index > -1) { + prefs.boundaries.hardLimits.splice(index, 1); + prefs.lastUpdated = new Date().toISOString(); + this.savePreferences(); + } + return true; + } + + /** + * Get statistics about preferences + * @returns {Object} Stats object + */ + getPreferenceStats() { + const prefs = this.getPreferences(); + + return { + totalCheckpoints: prefs.checkpointHistory.length, + lastUpdated: prefs.lastUpdated, + activeThemes: this.getActivePreferences(prefs.contentThemes).length, + activeVisuals: this.getActivePreferences(prefs.visualPreferences).length, + activeAudio: this.getActivePreferences(prefs.audioPreferences).length, + activeTones: this.getActivePreferences(prefs.captionTone).length, + discoveredFeatures: this.getDiscoveredFeatures().length, + enabledFeatures: this.getEnabledFeatures().length, + averageIntensity: this.getAverageIntensity(), + hardLimitsSet: prefs.boundaries.hardLimits.length, + softLimitsSet: prefs.boundaries.softLimits.length, + preferredDuration: prefs.sessionDuration.preferred + }; + } + + /** + * Calculate average intensity across all intensity categories + * @returns {number} Average intensity (1-5) + */ + getAverageIntensity() { + const prefs = this.getPreferences(); + const intensities = Object.values(prefs.intensity); + const sum = intensities.reduce((acc, val) => acc + val, 0); + return (sum / intensities.length).toFixed(1); + } + + /** + * Reset all preferences to defaults + * @returns {boolean} Success status + */ + resetPreferences() { + delete window.gameData.academyPreferences; + this.initializePreferences(); + return true; + } + + /** + * Save preferences to localStorage + */ + savePreferences() { + try { + localStorage.setItem('webGame-data', JSON.stringify(window.gameData)); + return true; + } catch (error) { + console.error('Failed to save preferences:', error); + if (error.name === 'QuotaExceededError') { + alert('⚠️ Storage full! Preferences could not be saved.\n\nThe app has cleared old data. Please try again.'); + } + return false; + } + } +} + +// Create global instance +window.preferenceManager = new PreferenceManager(); diff --git a/src/features/tasks/interactiveTaskManager.js b/src/features/tasks/interactiveTaskManager.js index 57ff252..e98f4ea 100644 --- a/src/features/tasks/interactiveTaskManager.js +++ b/src/features/tasks/interactiveTaskManager.js @@ -73,6 +73,155 @@ class InteractiveTaskManager { handler: this.createMirrorTask.bind(this), validator: this.validateMirrorTask.bind(this) }); + + // Academy Training Tasks + this.registerTaskType('edge', { + name: 'Edge Training', + description: 'Complete specified number of edges', + handler: this.createEdgeTask.bind(this), + validator: this.validateEdgeTask.bind(this) + }); + + this.registerTaskType('rhythm', { + name: 'Rhythm Pattern', + description: 'Follow a specific stroking rhythm', + handler: this.createRhythmTask.bind(this), + validator: this.validateRhythmTask.bind(this) + }); + + this.registerTaskType('add-library-directory', { + name: 'Add Library Directory', + description: 'Add a directory to your media library', + handler: this.createAddLibraryTask.bind(this), + validator: this.validateAddLibraryTask.bind(this) + }); + + this.registerTaskType('tag-files', { + name: 'Tag Files', + description: 'Tag files in your library', + handler: this.createTagFilesTask.bind(this), + validator: this.validateTagFilesTask.bind(this) + }); + + this.registerTaskType('enable-webcam', { + name: 'Enable Webcam', + description: 'Activate webcam for mirror viewing', + handler: this.createEnableWebcamTask.bind(this), + validator: this.validateEnableWebcamTask.bind(this) + }); + + this.registerTaskType('dual-video', { + name: 'Dual Video', + description: 'Watch two videos simultaneously', + handler: this.createDualVideoTask.bind(this), + validator: this.validateDualVideoTask.bind(this) + }); + + this.registerTaskType('tts-command', { + name: 'TTS Command', + description: 'Receive voice commands via text-to-speech', + handler: this.createTTSCommandTask.bind(this), + validator: this.validateTTSCommandTask.bind(this) + }); + + this.registerTaskType('quad-video', { + name: 'Quad Video', + description: 'Watch four videos simultaneously', + handler: this.createQuadVideoTask.bind(this), + validator: this.validateQuadVideoTask.bind(this) + }); + + this.registerTaskType('hypno-spiral', { + name: 'Hypno Spiral', + description: 'View hypnotic spiral overlay', + handler: this.createHypnoSpiralTask.bind(this), + validator: this.validateHypnoSpiralTask.bind(this) + }); + + this.registerTaskType('video-start', { + name: 'Start Video', + description: 'Start a video player', + handler: this.createVideoStartTask.bind(this), + validator: this.validateVideoStartTask.bind(this) + }); + + this.registerTaskType('update-preferences', { + name: 'Update Preferences', + description: 'Update Academy preferences at checkpoint', + handler: this.createUpdatePreferencesTask.bind(this), + validator: this.validateUpdatePreferencesTask.bind(this) + }); + + this.registerTaskType('free-edge-session', { + name: 'Free Edge Session', + description: 'Free-form edging session with features enabled', + handler: this.createFreeEdgeSessionTask.bind(this), + validator: this.validateFreeEdgeSessionTask.bind(this) + }); + + // Advanced Training Arc Actions (Levels 11-20) + this.registerTaskType('hypno-caption-combo', { + name: 'Hypno Caption Combo', + description: 'Hypno spiral with timed caption overlays', + handler: this.createHypnoCaptionComboTask.bind(this), + validator: this.validateTimedTask.bind(this) + }); + + this.registerTaskType('dynamic-captions', { + name: 'Dynamic Captions', + description: 'Preference-based caption display', + handler: this.createDynamicCaptionsTask.bind(this), + validator: this.validateTimedTask.bind(this) + }); + + this.registerTaskType('tts-hypno-sync', { + name: 'TTS Hypno Sync', + description: 'Voice commands synchronized with hypno spiral', + handler: this.createTTSHypnoSyncTask.bind(this), + validator: this.validateTimedTask.bind(this) + }); + + this.registerTaskType('sensory-overload', { + name: 'Sensory Overload', + description: 'All features combined in one session', + handler: this.createSensoryOverloadTask.bind(this), + validator: this.validateTimedTask.bind(this) + }); + + this.registerTaskType('enable-interruptions', { + name: 'Enable Interruptions', + description: 'Activate random interruption system', + handler: this.createEnableInterruptionsTask.bind(this), + validator: this.validateInstantTask.bind(this) + }); + + this.registerTaskType('denial-training', { + name: 'Denial Training', + description: 'Timed stroking/stopping periods', + handler: this.createDenialTrainingTask.bind(this), + validator: this.validateTimedTask.bind(this) + }); + + this.registerTaskType('stop-stroking', { + name: 'Stop Stroking', + description: 'Enforced hands-off period', + handler: this.createStopStrokingTask.bind(this), + validator: this.validateTimedTask.bind(this) + }); + + this.registerTaskType('enable-popups', { + name: 'Enable Popups', + description: 'Activate random popup image system', + handler: this.createEnablePopupsTask.bind(this), + validator: this.validateInstantTask.bind(this) + }); + + this.registerTaskType('popup-image', { + name: 'Popup Image', + description: 'Display specific popup image', + handler: this.createPopupImageTask.bind(this), + validator: this.validateTimedTask.bind(this) + }); } /** @@ -2011,6 +2160,12 @@ class InteractiveTaskManager { } else if (step.type === 'mirror-action') { // Handle mirror-based action steps - create the mirror task directly this.createMirrorTask(task, choicesEl); + } else if (step.type === 'inventory-check') { + // Handle inventory questionnaire + this.displayInventoryQuestionnaire(task, scenario, step, choicesEl); + } else if (step.type === 'path-generation') { + // Handle dynamic path generation based on inventory + this.generateInventoryPath(task, scenario, step, choicesEl); } else if (step.type === 'text') { // Handle text-only steps that just need a continue button const continueBtn = document.createElement('button'); @@ -2046,6 +2201,13 @@ class InteractiveTaskManager { choicesEl.appendChild(endingDiv); + // For inventory-based endings, populate the items list + if (task.scenarioState.tier && task.scenarioState.inventoryManager) { + setTimeout(() => { + this.populateInventoryItemsList(task.scenarioState.tier, task.scenarioState.inventoryManager); + }, 100); + } + // Enable completion button setTimeout(() => { this.enableInteractiveControls(true); @@ -3170,7 +3332,18 @@ class InteractiveTaskManager { * Get photo requirements from step */ getPhotoRequirements(step) { - // First check if step has explicit photoCount property + // First check if step has photoRequirements object (inventory-based progression) + if (step.photoRequirements) { + return { + count: step.photoRequirements.count || 3, + description: `Take ${step.photoRequirements.count || 3} photos to complete this task`, + items: step.photoRequirements.items || [], + pose: step.photoRequirements.pose || null, + edging: step.photoRequirements.edging || false + }; + } + + // Check if step has explicit photoCount property if (step.photoCount) { return { count: step.photoCount, @@ -4142,6 +4315,2160 @@ class InteractiveTaskManager { } } + /** + * Display inventory questionnaire + */ + displayInventoryQuestionnaire(task, scenario, step, choicesEl) { + console.log('📋 Displaying inventory questionnaire'); + + // Initialize inventory in scenario state if not exists + if (!task.scenarioState.inventory) { + task.scenarioState.inventory = {}; + } + + const categories = step.inventoryCategories || {}; + const categoryKeys = Object.keys(categories); + + // Build questionnaire HTML + let questionnaireHTML = '
'; + + categoryKeys.forEach(categoryKey => { + const category = categories[categoryKey]; + questionnaireHTML += ` +
+

${category.title}

+
+ `; + + Object.keys(category.items).forEach(itemKey => { + const item = category.items[itemKey]; + const currentValue = task.scenarioState.inventory[itemKey] || (item.type === 'boolean' ? false : 'none'); + + if (item.type === 'boolean') { + // Boolean checkbox + questionnaireHTML += ` +
+ +
+ `; + } else { + // Dropdown select + questionnaireHTML += ` +
+ +
+ `; + } + }); + + questionnaireHTML += ` +
+
+ `; + }); + + questionnaireHTML += '
'; + + // Display the questionnaire + choicesEl.innerHTML = questionnaireHTML; + + // Add submit button + const submitBtn = document.createElement('button'); + submitBtn.className = 'scenario-choice primary'; + submitBtn.innerHTML = '
Submit Inventory
'; + submitBtn.addEventListener('click', () => { + // Collect all inventory values + document.querySelectorAll('.inventory-select').forEach(select => { + const itemKey = select.dataset.item; + task.scenarioState.inventory[itemKey] = select.value; + }); + + document.querySelectorAll('.inventory-checkbox').forEach(checkbox => { + const itemKey = checkbox.dataset.item; + task.scenarioState.inventory[itemKey] = checkbox.checked; + }); + + console.log('📦 Collected inventory:', task.scenarioState.inventory); + + // Move to next step + const nextStep = step.nextStep; + task.scenarioState.currentStep = nextStep; + task.scenarioState.stepNumber++; + this.displayScenarioStep(task, scenario, nextStep); + }); + + choicesEl.appendChild(submitBtn); + } + + /** + * Populate inventory items list in certificate ending + */ + populateInventoryItemsList(tier, inventoryManager) { + const listEl = document.getElementById(`tier-${tier}-items-list`); + if (!listEl) { + console.warn(`Could not find tier-${tier}-items-list element`); + return; + } + + const summary = inventoryManager.getInventorySummary(); + let itemsHTML = ''; + + // Combine all items into one list + const allItems = [ + ...summary.clothing.map(item => `👗 ${item}`), + ...summary.accessories.map(item => `💄 ${item}`), + ...summary.toys.map(item => `🔞 ${item}`), + ...summary.environment.map(item => `📸 ${item}`) + ]; + + if (allItems.length > 0) { + itemsHTML = `
    + ${allItems.map(item => `
  • ${item}
  • `).join('')} +
`; + } else { + itemsHTML = '

No items used

'; + } + + listEl.innerHTML = itemsHTML; + } + + /** + * Generate dynamic photo progression based on inventory + */ + async generateInventoryPath(task, scenario, step, choicesEl) { + console.log('🎯 Generating inventory-based path'); + + // Load InventoryManager if not already loaded + if (!window.InventoryManager) { + console.error('❌ InventoryManager not loaded!'); + return; + } + + // Create inventory manager instance + const inventoryManager = new window.InventoryManager(); + inventoryManager.setInventory(task.scenarioState.inventory); + + // Get tier and summary + const tier = inventoryManager.tier; + const summary = inventoryManager.getInventorySummary(); + const photoCount = inventoryManager.getTotalPhotos(); + + console.log(`📊 Tier ${tier}: ${summary.totalItems} items, ${photoCount} photos`); + + // Store in scenario state + task.scenarioState.tier = tier; + task.scenarioState.photoCount = photoCount; + task.scenarioState.inventoryManager = inventoryManager; + + // Generate photo progression + const progression = inventoryManager.generatePhotoProgression(); + console.log(`📸 Generated ${progression.length} photo challenges`); + + // Load pose bank + if (!window.InventoryPoseBank) { + console.error('❌ InventoryPoseBank not loaded!'); + return; + } + + // Dynamically add challenge steps to scenario + progression.forEach((challenge, index) => { + const stepId = `challenge_${index + 1}`; + const isLastChallenge = index === progression.length - 1; + const nextStepId = isLastChallenge ? `tier_${tier}_ending` : `challenge_${index + 2}`; + + // Create photo-verification step + scenario.steps[stepId] = { + type: 'photo-verification', + mood: 'progressive', + story: challenge.instruction, + photoRequirements: { + items: challenge.requiredItems, + pose: challenge.pose, + edging: challenge.edging, + count: 3 + }, + nextStep: nextStepId + }; + }); + + console.log(`✅ Added ${progression.length} challenge steps to scenario`); + + // Display summary + const summaryHTML = ` +
+

📊 Your Photo Journey

+
Tier ${tier}
+
+
+ Items Available: + ${summary.totalItems} +
+
+ Photos Required: + ${photoCount} +
+
+ +
+ ${summary.clothing.length > 0 ? ` +
+

👗 Clothing

+
    ${summary.clothing.map(item => `
  • ${item}
  • `).join('')}
+
+ ` : ''} + + ${summary.accessories.length > 0 ? ` +
+

💄 Accessories

+
    ${summary.accessories.map(item => `
  • ${item}
  • `).join('')}
+
+ ` : ''} + + ${summary.toys.length > 0 ? ` +
+

🔞 Toys

+
    ${summary.toys.map(item => `
  • ${item}
  • `).join('')}
+
+ ` : ''} + + ${summary.environment.length > 0 ? ` +
+

📸 Environment

+
    ${summary.environment.map(item => `
  • ${item}
  • `).join('')}
+
+ ` : ''} +
+
+ `; + + choicesEl.innerHTML = summaryHTML; + + // Add choice buttons + const choicesHTML = step.choices.map((choice, index) => { + const btnClass = index === 0 ? 'primary' : 'secondary'; + const btn = document.createElement('button'); + btn.className = `scenario-choice ${btnClass}`; + btn.innerHTML = `
${choice.text}
`; + btn.addEventListener('click', () => { + const nextStep = choice.nextStep; + task.scenarioState.currentStep = nextStep; + task.scenarioState.stepNumber++; + this.displayScenarioStep(task, scenario, nextStep); + }); + return btn; + }).forEach(btn => choicesEl.appendChild(btn)); + } + + // ======================================== + // ACADEMY TRAINING ACTION HANDLERS + // ======================================== + + /** + * Edge Training Task - Timed edging/gooning session + */ + async createEdgeTask(task, container) { + const duration = task.params?.duration || 300; // Default 5 minutes + const instruction = task.params?.instruction || 'Edge and goon for the full duration'; + const withVideo = task.params?.keepVideoPlaying || false; + + container.innerHTML = ` +
+

🎯 Edge Training

+

${instruction}

+ ${withVideo ? '
' : ''} +
+
+ Session Duration: + ${Math.floor(duration / 60)} minutes ${duration % 60} seconds +
+
+
+
--:--
+
+
+
+
+
+ + ${withVideo ? '' : ''} +
+
+
+ `; + + const btn = container.querySelector('#start-edge-session-btn'); + const skipVideoBtn = withVideo ? container.querySelector('#skip-edge-video-btn') : null; + const statusArea = container.querySelector('#edge-status'); + const timerDisplay = container.querySelector('.time-remaining'); + const progressFill = container.querySelector('#edge-progress'); + const videoContainer = withVideo ? container.querySelector('#edge-video-container') : null; + + let availableVideos = []; + + const playRandomEdgeVideo = async () => { + if (!withVideo || !videoContainer || !window.videoPlayerManager) return; + if (availableVideos.length === 0) return; + + const randomVideo = availableVideos[Math.floor(Math.random() * availableVideos.length)]; + try { + await window.videoPlayerManager.playTaskVideo(randomVideo, videoContainer); + } catch (error) { + console.warn('Failed to play video for edge session:', error); + } + }; + + if (skipVideoBtn) { + skipVideoBtn.addEventListener('click', async () => { + await playRandomEdgeVideo(); + statusArea.innerHTML = '
⏭️ Skipped to new video - keep edging!
'; + }); + } + + btn.addEventListener('click', async () => { + btn.disabled = true; + btn.style.display = 'none'; + + // Start video if requested + if (withVideo && videoContainer && window.videoPlayerManager) { + availableVideos = window.videoPlayerManager.videoLibrary?.background || []; + if (availableVideos.length > 0) { + await playRandomEdgeVideo(); + if (skipVideoBtn) skipVideoBtn.style.display = 'inline-block'; + } + } + + let timeRemaining = duration; + timerDisplay.textContent = `${Math.floor(timeRemaining / 60)}:${(timeRemaining % 60).toString().padStart(2, '0')}`; + statusArea.innerHTML = '
🎯 Edge and stroke... don\'t stop until time is up!
'; + + const timerInterval = setInterval(() => { + timeRemaining--; + + const minutes = Math.floor(timeRemaining / 60); + const seconds = timeRemaining % 60; + timerDisplay.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`; + + const progress = ((duration - timeRemaining) / duration) * 100; + progressFill.style.width = `${progress}%`; + + if (timeRemaining <= 0) { + clearInterval(timerInterval); + timerDisplay.textContent = 'COMPLETE!'; + timerDisplay.style.color = 'var(--color-success, #4caf50)'; + statusArea.innerHTML = '
✅ Edge training session complete!
'; + + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }, 1000); + }); + } + + validateEdgeTask(task) { + return task.completed === true; + } + + /** + * Rhythm Pattern Task - Follow stroking rhythm + */ + async createRhythmTask(task, container) { + const pattern = task.params?.pattern || 'slow-fast-slow'; + const duration = task.params?.duration || 120; + + const patterns = { + 'slow-fast-slow': [60, 120, 60], + 'fast-slow-fast': [120, 60, 120], + 'steady': [90, 90, 90], + 'escalating': [60, 90, 120, 150] + }; + + const bpmSequence = patterns[pattern] || patterns['steady']; + let currentPhase = 0; + let timeRemaining = duration; + + container.innerHTML = ` +
+

🎵 Rhythm Pattern: ${pattern}

+
+
+
+ ${bpmSequence[0]} BPM +
+
+ Phase ${currentPhase + 1} of ${bpmSequence.length} +
+
+
+ ${timeRemaining}s remaining +
+
+ `; + + const metronomeVisual = container.querySelector('#metronome-visual'); + const bpmDisplay = container.querySelector('.bpm-value'); + const timerDisplay = container.querySelector('#rhythm-timer'); + const phaseIndicator = container.querySelector('.phase-indicator'); + + // Start metronome animation + let bpm = bpmSequence[currentPhase]; + let beatInterval = (60 / bpm) * 1000; + + const beat = () => { + metronomeVisual.classList.add('beat'); + setTimeout(() => metronomeVisual.classList.remove('beat'), 100); + }; + + let beatTimer = setInterval(beat, beatInterval); + + // Countdown timer and phase progression + const phaseDuration = duration / bpmSequence.length; + let phaseTime = phaseDuration; + + const countdown = setInterval(() => { + timeRemaining--; + phaseTime--; + timerDisplay.textContent = `${timeRemaining}s`; + + if (phaseTime <= 0 && currentPhase < bpmSequence.length - 1) { + currentPhase++; + phaseTime = phaseDuration; + bpm = bpmSequence[currentPhase]; + beatInterval = (60 / bpm) * 1000; + + clearInterval(beatTimer); + beatTimer = setInterval(beat, beatInterval); + + bpmDisplay.textContent = bpm; + phaseIndicator.textContent = `Phase ${currentPhase + 1} of ${bpmSequence.length}`; + } + + if (timeRemaining <= 0) { + clearInterval(countdown); + clearInterval(beatTimer); + task.completed = true; + + container.innerHTML += '
✅ Rhythm pattern complete!
'; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }, 1000); + + // Store cleanup + task.cleanup = () => { + clearInterval(countdown); + clearInterval(beatTimer); + }; + } + + validateRhythmTask(task) { + return task.completed === true; + } + + /** + * Add Library Directory Task + */ + async createAddLibraryTask(task, container) { + const suggestedDir = task.params?.directory || ''; + const suggestedTags = task.params?.suggestedTags || []; + + container.innerHTML = ` +
+

📁 Add Library Directory

+

Add a directory containing your media files to The Academy library.

+ ${suggestedDir ? `

Suggested: ${suggestedDir}

` : ''} + ${suggestedTags.length > 0 ? ` +

Suggested tags: ${suggestedTags.map(t => `${t}`).join(' ')}

+ ` : ''} + +
+
+ `; + + const btn = container.querySelector('#select-directory-btn'); + const resultArea = container.querySelector('#directory-result'); + + btn.addEventListener('click', async () => { + if (window.libraryManager) { + try { + const result = await window.libraryManager.addDirectory(suggestedTags); + if (result) { + resultArea.innerHTML = ` +
+ ✅ Directory added successfully! +

Files found: ${result.fileCount || 'Scanning...'}

+
+ `; + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + } catch (error) { + resultArea.innerHTML = `
Error: ${error.message}
`; + } + } else { + resultArea.innerHTML = '
Library manager not available
'; + } + }); + } + + validateAddLibraryTask(task) { + return task.completed === true; + } + + /** + * Tag Files Task + */ + async createTagFilesTask(task, container) { + const directory = task.params?.directory || ''; + const minFiles = task.params?.minFiles || 10; + const suggestedTags = task.params?.suggestedTags || []; + + container.innerHTML = ` +
+

🏷️ Tag Your Files

+

Tag at least ${minFiles} files in your library to improve content filtering.

+ ${directory ? `

Focus on: ${directory}

` : ''} + ${suggestedTags.length > 0 ? ` +

Suggested tags: ${suggestedTags.map(t => `${t}`).join(' ')}

+ ` : ''} +
+ 0 / ${minFiles} files tagged +
+ +
+ `; + + const btn = container.querySelector('#open-tagging-btn'); + const progressEl = container.querySelector('#files-tagged'); + + btn.addEventListener('click', () => { + // TODO: Implement tagging interface UI + // For now, auto-complete the task + progressEl.textContent = minFiles; + task.completed = true; + btn.disabled = true; + btn.textContent = '✅ Tagging Complete (Auto)'; + + const statusArea = container.querySelector('.status-area'); + if (statusArea) { + statusArea.innerHTML = '
ℹ️ Tagging interface will be implemented in Phase 8
'; + } + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + }); + } + + validateTagFilesTask(task) { + return task.completed === true; + } + + /** + * Enable Webcam Task + */ + async createEnableWebcamTask(task, container) { + const instruction = task.params?.instruction || 'Turn on your webcam to watch yourself'; + + container.innerHTML = ` +
+

📹 Enable Webcam

+

${instruction}

+
+ +
+ +
+
+ `; + + const btn = container.querySelector('#enable-webcam-btn'); + const statusArea = container.querySelector('#webcam-status'); + const videoEl = container.querySelector('#webcam-video'); + + btn.addEventListener('click', async () => { + btn.disabled = true; + btn.textContent = 'Requesting permission...'; + + try { + // Request webcam access directly using browser API + const stream = await navigator.mediaDevices.getUserMedia({ + video: { + width: { ideal: 1280 }, + height: { ideal: 720 } + }, + audio: false + }); + + // Display webcam feed + videoEl.srcObject = stream; + videoEl.style.display = 'block'; + + statusArea.innerHTML = '
✅ Webcam active - Watch yourself as you train
'; + btn.textContent = '✅ Webcam Started'; + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + + // Store stream reference for cleanup + task.webcamStream = stream; + + } catch (error) { + console.error('Webcam error:', error); + + let errorMsg = 'Failed to access webcam'; + if (error.name === 'NotAllowedError') { + errorMsg = 'Webcam permission denied - you can continue without it'; + } else if (error.name === 'NotFoundError') { + errorMsg = 'No webcam found - you can continue without it'; + } + + statusArea.innerHTML = `
ℹ️ ${errorMsg}
`; + btn.textContent = '⚠️ Webcam Unavailable'; + + // Auto-complete even on error + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }); + } + + validateEnableWebcamTask(task) { + return task.completed === true; + } + + /** + * Dual Video Task + */ + async createDualVideoTask(task, container) { + const mainVideo = task.params?.mainVideo || 'focus'; + const pipVideo = task.params?.pipVideo || 'overlay'; + const pipPosition = task.params?.pipPosition || 'bottom-right'; + const minDuration = task.params?.minDuration || 120; // Default 2 minutes + + container.innerHTML = ` +
+

🎬 Dual Video Mode

+

Watch two videos simultaneously - main video with picture-in-picture overlay.

+

Minimum viewing time: ${minDuration} seconds

+
+
+ + +
+ +
+
+ `; + + const btn = container.querySelector('#start-dual-video-btn'); + const skipBtn = container.querySelector('#skip-dual-video-btn'); + const statusArea = container.querySelector('#dual-video-status'); + const mainContainer = container.querySelector('#dual-video-main-container'); + const timerDisplay = container.querySelector('#dual-video-timer'); + + let availableVideos = []; + + const playDualVideos = async () => { + if (availableVideos.length < 2) return; + + // Select two random videos + const video1 = availableVideos[Math.floor(Math.random() * availableVideos.length)]; + let video2 = availableVideos[Math.floor(Math.random() * availableVideos.length)]; + while (video2 === video1 && availableVideos.length > 1) { + video2 = availableVideos[Math.floor(Math.random() * availableVideos.length)]; + } + + // Clear existing videos + mainContainer.innerHTML = ''; + + // Play main video + await window.videoPlayerManager.playTaskVideo(video1, mainContainer); + + // Play overlay video (PiP style) + await window.videoPlayerManager.playOverlayVideo(video2); + + // Position the overlay player as PiP with draggable and resizable + if (window.videoPlayerManager.overlayPlayer) { + const pipPlayer = window.videoPlayerManager.overlayPlayer; + pipPlayer.style.position = 'fixed'; + pipPlayer.style.width = '300px'; + pipPlayer.style.height = 'auto'; + pipPlayer.style.zIndex = '100'; + pipPlayer.style.boxShadow = '0 0 20px rgba(0,0,0,0.5)'; + pipPlayer.style.cursor = 'move'; + pipPlayer.style.border = '2px solid rgba(255,255,255,0.3)'; + pipPlayer.style.borderRadius = '8px'; + + // Position based on parameter + const positions = { + 'bottom-right': { bottom: '20px', right: '20px', top: 'auto', left: 'auto' }, + 'bottom-left': { bottom: '20px', left: '20px', top: 'auto', right: 'auto' }, + 'top-right': { top: '20px', right: '20px', bottom: 'auto', left: 'auto' }, + 'top-left': { top: '20px', left: '20px', bottom: 'auto', right: 'auto' } + }; + + const pos = positions[pipPosition] || positions['bottom-right']; + Object.assign(pipPlayer.style, pos); + + // Wrap in container for resize handle + const pipContainer = document.createElement('div'); + pipContainer.style.cssText = ` + position: fixed; + ${pos.top ? 'top: ' + pos.top : ''}; + ${pos.bottom ? 'bottom: ' + pos.bottom : ''}; + ${pos.left ? 'left: ' + pos.left : ''}; + ${pos.right ? 'right: ' + pos.right : ''}; + z-index: 100; + `; + + // Move player into container + pipPlayer.parentElement.insertBefore(pipContainer, pipPlayer); + pipContainer.appendChild(pipPlayer); + pipPlayer.style.position = 'relative'; + pipPlayer.style.top = 'auto'; + pipPlayer.style.bottom = 'auto'; + pipPlayer.style.left = 'auto'; + pipPlayer.style.right = 'auto'; + + // Create resize handle + const resizeHandle = document.createElement('div'); + resizeHandle.style.cssText = ` + position: absolute; + bottom: 2px; + right: 2px; + width: 20px; + height: 20px; + background: rgba(255,255,255,0.7); + cursor: nwse-resize; + border-radius: 0 0 6px 0; + z-index: 101; + `; + resizeHandle.innerHTML = '⋰'; + resizeHandle.style.textAlign = 'center'; + resizeHandle.style.lineHeight = '20px'; + resizeHandle.style.fontSize = '12px'; + pipContainer.appendChild(resizeHandle); + + // Make draggable + let isDragging = false; + let isResizing = false; + let startX, startY, startWidth, startHeight; + let currentX, currentY; + + // Drag functionality + pipPlayer.addEventListener('mousedown', (e) => { + if (e.target === resizeHandle) return; + isDragging = true; + const rect = pipContainer.getBoundingClientRect(); + startX = e.clientX - rect.left; + startY = e.clientY - rect.top; + pipPlayer.style.opacity = '0.8'; + e.preventDefault(); + }); + + // Resize functionality + resizeHandle.addEventListener('mousedown', (e) => { + e.stopPropagation(); + e.preventDefault(); + isResizing = true; + startX = e.clientX; + startY = e.clientY; + startWidth = pipPlayer.offsetWidth; + startHeight = pipPlayer.offsetHeight; + }); + + document.addEventListener('mousemove', (e) => { + if (isDragging) { + currentX = e.clientX - startX; + currentY = e.clientY - startY; + + // Keep within viewport bounds + currentX = Math.max(0, Math.min(currentX, window.innerWidth - pipContainer.offsetWidth)); + currentY = Math.max(0, Math.min(currentY, window.innerHeight - pipContainer.offsetHeight)); + + pipContainer.style.left = currentX + 'px'; + pipContainer.style.top = currentY + 'px'; + pipContainer.style.right = 'auto'; + pipContainer.style.bottom = 'auto'; + } else if (isResizing) { + const deltaX = e.clientX - startX; + const newWidth = Math.max(200, Math.min(800, startWidth + deltaX)); + pipPlayer.style.width = newWidth + 'px'; + } + }); + + document.addEventListener('mouseup', () => { + if (isDragging) { + isDragging = false; + pipPlayer.style.opacity = '1'; + } + if (isResizing) { + isResizing = false; + } + }); + } + }; + + skipBtn.addEventListener('click', async () => { + if (availableVideos.length >= 2) { + await playDualVideos(); + statusArea.innerHTML = '
⏭️ Loaded new videos
'; + } + }); + + btn.addEventListener('click', async () => { + btn.disabled = true; + btn.textContent = 'Loading...'; + + if (!window.videoPlayerManager) { + statusArea.innerHTML = '
⚠️ Video manager not initialized
'; + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + return; + } + + try { + const videos = window.videoPlayerManager.videoLibrary?.background || []; + + if (videos.length < 2) { + statusArea.innerHTML = '
ℹ️ Need at least 2 videos - continuing anyway
'; + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + return; + } + + availableVideos = videos; + await playDualVideos(); + + btn.style.display = 'none'; + skipBtn.style.display = 'inline-block'; + + // Position the overlay player as PiP with draggable and resizable + if (window.videoPlayerManager.overlayPlayer) { + const pipPlayer = window.videoPlayerManager.overlayPlayer; + pipPlayer.style.position = 'fixed'; + pipPlayer.style.width = '300px'; + pipPlayer.style.height = 'auto'; + pipPlayer.style.zIndex = '100'; + pipPlayer.style.boxShadow = '0 0 20px rgba(0,0,0,0.5)'; + pipPlayer.style.cursor = 'move'; + pipPlayer.style.border = '2px solid rgba(255,255,255,0.3)'; + pipPlayer.style.borderRadius = '8px'; + + // Position based on parameter + const positions = { + 'bottom-right': { bottom: '20px', right: '20px', top: 'auto', left: 'auto' }, + 'bottom-left': { bottom: '20px', left: '20px', top: 'auto', right: 'auto' }, + 'top-right': { top: '20px', right: '20px', bottom: 'auto', left: 'auto' }, + 'top-left': { top: '20px', left: '20px', bottom: 'auto', right: 'auto' } + }; + + const pos = positions[pipPosition] || positions['bottom-right']; + Object.assign(pipPlayer.style, pos); + + // Wrap in container for resize handle + const pipContainer = document.createElement('div'); + pipContainer.style.cssText = ` + position: fixed; + ${pos.top ? 'top: ' + pos.top : ''}; + ${pos.bottom ? 'bottom: ' + pos.bottom : ''}; + ${pos.left ? 'left: ' + pos.left : ''}; + ${pos.right ? 'right: ' + pos.right : ''}; + z-index: 100; + `; + + // Move player into container + pipPlayer.parentElement.insertBefore(pipContainer, pipPlayer); + pipContainer.appendChild(pipPlayer); + pipPlayer.style.position = 'relative'; + pipPlayer.style.top = 'auto'; + pipPlayer.style.bottom = 'auto'; + pipPlayer.style.left = 'auto'; + pipPlayer.style.right = 'auto'; + + // Create resize handle + const resizeHandle = document.createElement('div'); + resizeHandle.style.cssText = ` + position: absolute; + bottom: 2px; + right: 2px; + width: 20px; + height: 20px; + background: rgba(255,255,255,0.7); + cursor: nwse-resize; + border-radius: 0 0 6px 0; + z-index: 101; + `; + resizeHandle.innerHTML = '⋰'; + resizeHandle.style.textAlign = 'center'; + resizeHandle.style.lineHeight = '20px'; + resizeHandle.style.fontSize = '12px'; + pipContainer.appendChild(resizeHandle); + + // Make draggable + let isDragging = false; + let isResizing = false; + let startX, startY, startWidth, startHeight; + let currentX, currentY; + + // Drag functionality + pipPlayer.addEventListener('mousedown', (e) => { + if (e.target === resizeHandle) return; + isDragging = true; + const rect = pipContainer.getBoundingClientRect(); + startX = e.clientX - rect.left; + startY = e.clientY - rect.top; + pipPlayer.style.opacity = '0.8'; + e.preventDefault(); + }); + + // Resize functionality + resizeHandle.addEventListener('mousedown', (e) => { + e.stopPropagation(); + e.preventDefault(); + isResizing = true; + startX = e.clientX; + startY = e.clientY; + startWidth = pipPlayer.offsetWidth; + startHeight = pipPlayer.offsetHeight; + }); + + document.addEventListener('mousemove', (e) => { + if (isDragging) { + currentX = e.clientX - startX; + currentY = e.clientY - startY; + + // Keep within viewport bounds + currentX = Math.max(0, Math.min(currentX, window.innerWidth - pipContainer.offsetWidth)); + currentY = Math.max(0, Math.min(currentY, window.innerHeight - pipContainer.offsetHeight)); + + pipContainer.style.left = currentX + 'px'; + pipContainer.style.top = currentY + 'px'; + pipContainer.style.right = 'auto'; + pipContainer.style.bottom = 'auto'; + } else if (isResizing) { + const deltaX = e.clientX - startX; + const newWidth = Math.max(200, Math.min(800, startWidth + deltaX)); + pipPlayer.style.width = newWidth + 'px'; + } + }); + + document.addEventListener('mouseup', () => { + if (isDragging) { + isDragging = false; + pipPlayer.style.opacity = '1'; + } + if (isResizing) { + isResizing = false; + } + }); + } + + btn.style.display = 'none'; + timerDisplay.style.display = 'block'; + + // Start countdown timer + let remainingTime = minDuration; + timerDisplay.innerHTML = `⏱️ Keep watching both videos... ${remainingTime}s remaining`; + + const timerInterval = setInterval(() => { + remainingTime--; + + if (remainingTime > 0) { + timerDisplay.innerHTML = `⏱️ Keep watching both videos... ${remainingTime}s remaining`; + } else { + clearInterval(timerInterval); + timerDisplay.innerHTML = '✅ Minimum viewing time complete!'; + timerDisplay.style.color = 'var(--color-success, #4caf50)'; + + statusArea.innerHTML = '
✅ Dual video session complete
'; + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }, 1000); + + } catch (error) { + console.error('Dual video error:', error); + statusArea.innerHTML = `
⚠️ ${error.message} - Continuing anyway
`; + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }); + } + + validateDualVideoTask(task) { + return task.completed === true; + } + + /** + * TTS Command Task + */ + async createTTSCommandTask(task, container) { + const text = task.params?.text || 'Good gooner. Edge again.'; + const voice = task.params?.voice || 'feminine'; + + container.innerHTML = ` +
+

🎤 Voice Command

+

Listen to the voice command and follow instructions.

+
"${text}"
+ +
+ `; + + const btn = container.querySelector('#play-tts-btn'); + + btn.addEventListener('click', async () => { + if (this.voiceManager && this.ttsEnabled) { + try { + await this.voiceManager.speak(text); + task.completed = true; + btn.disabled = true; + btn.textContent = '✅ Command Received'; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } catch (error) { + console.error('TTS error:', error); + } + } else { + // TTS not available, auto-complete + task.completed = true; + btn.disabled = true; + btn.textContent = '✅ Command Received (TTS unavailable)'; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }); + } + + validateTTSCommandTask(task) { + return task.completed === true; + } + + /** + * Quad Video Task + */ + async createQuadVideoTask(task, container) { + const layout = task.params?.layout || 'grid'; + const minDuration = task.params?.minDuration || 180; // Default 3 minutes + + container.innerHTML = ` +
+

🎬 Quad Video Mode

+

Watch four videos simultaneously in a ${layout} layout.

+

Minimum viewing time: ${minDuration} seconds

+ +
+ + +
+ +
+
+ `; + + const btn = container.querySelector('#start-quad-video-btn'); + const skipBtn = container.querySelector('#skip-quad-video-btn'); + const statusArea = container.querySelector('#quad-video-status'); + const gridContainer = container.querySelector('#quad-video-grid'); + const timerDisplay = container.querySelector('#quad-video-timer'); + + let availableVideos = []; + + const playQuadVideos = async () => { + if (availableVideos.length < 4) return; + + // Select 4 random unique videos + const selectedVideos = []; + const availableIndices = [...Array(availableVideos.length).keys()]; + for (let i = 0; i < 4; i++) { + const randomIndex = Math.floor(Math.random() * availableIndices.length); + selectedVideos.push(availableVideos[availableIndices[randomIndex]]); + availableIndices.splice(randomIndex, 1); + } + + // Create 4 video elements in the grid + gridContainer.style.display = 'block'; + + for (let i = 0; i < 4; i++) { + const videoContainer = container.querySelector(`#quad-video-${i + 1}`); + videoContainer.innerHTML = ''; // Clear existing video + const videoEl = document.createElement('video'); + videoEl.style.cssText = 'width: 100%; height: auto; display: block;'; + videoEl.autoplay = true; + videoEl.loop = true; + videoEl.muted = i > 0; // Only first video has sound + + const videoPath = selectedVideos[i]; + videoEl.src = window.videoPlayerManager.getVideoPath(videoPath); + + videoContainer.appendChild(videoEl); + + try { + await videoEl.play(); + } catch (e) { + console.warn(`Failed to play video ${i + 1}:`, e); + } + } + }; + + skipBtn.addEventListener('click', async () => { + if (availableVideos.length >= 4) { + await playQuadVideos(); + statusArea.innerHTML = '
⏭️ Loaded 4 new videos
'; + } + }); + + btn.addEventListener('click', async () => { + btn.disabled = true; + btn.textContent = 'Loading...'; + + if (!window.videoPlayerManager) { + statusArea.innerHTML = '
⚠️ Video manager not initialized
'; + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + return; + } + + try { + const videos = window.videoPlayerManager.videoLibrary?.background || []; + + if (videos.length < 4) { + statusArea.innerHTML = '
ℹ️ Need at least 4 videos - continuing anyway
'; + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + return; + } + + availableVideos = videos; + await playQuadVideos(); + + btn.style.display = 'none'; + skipBtn.style.display = 'inline-block'; + timerDisplay.style.display = 'block'; + + // Start countdown timer + let remainingTime = minDuration; + timerDisplay.innerHTML = `⏱️ Keep watching all 4 videos... ${remainingTime}s remaining`; + + const timerInterval = setInterval(() => { + remainingTime--; + + if (remainingTime > 0) { + timerDisplay.innerHTML = `⏱️ Keep watching all 4 videos... ${remainingTime}s remaining`; + } else { + clearInterval(timerInterval); + timerDisplay.innerHTML = '✅ Minimum viewing time complete!'; + timerDisplay.style.color = 'var(--color-success, #4caf50)'; + + statusArea.innerHTML = '
✅ Quad video session complete
'; + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }, 1000); + + } catch (error) { + console.error('Quad video error:', error); + statusArea.innerHTML = `
⚠️ ${error.message} - Continuing anyway
`; + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }); + } + + validateQuadVideoTask(task) { + return task.completed === true; + } + + /** + * Hypno Spiral Task + */ + async createHypnoSpiralTask(task, container) { + const duration = task.params?.duration || 120; + const overlay = task.params?.overlay || true; + const opacity = task.params?.opacity || 0.5; + + let timeRemaining = duration; + + container.innerHTML = ` +
+

🌀 Hypnotic Spiral

+

Stare at the spiral. Let it pull you deeper.

+
+
+
+
+ ${timeRemaining}s remaining +
+ +
+ `; + + const btn = container.querySelector('#start-hypno-btn'); + const spiral = container.querySelector('#hypno-spiral'); + const timerDisplay = container.querySelector('#hypno-timer'); + + btn.addEventListener('click', () => { + btn.disabled = true; + spiral.classList.add('spinning'); + + if (overlay) { + spiral.style.opacity = opacity; + } + + const countdown = setInterval(() => { + timeRemaining--; + timerDisplay.textContent = `${timeRemaining}s`; + + if (timeRemaining <= 0) { + clearInterval(countdown); + task.completed = true; + spiral.classList.remove('spinning'); + + container.innerHTML += '
✅ Spiral session complete
'; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }, 1000); + + task.cleanup = () => clearInterval(countdown); + }); + } + + validateHypnoSpiralTask(task) { + return task.completed === true; + } + + /** + * Video Start Task - Start a video player + */ + async createVideoStartTask(task, container) { + const player = task.params?.player || 'task'; + const tags = task.params?.tags || []; + const minDuration = task.params?.minDuration || 60; // Default 60 seconds minimum viewing + + container.innerHTML = ` +
+

🎬 Video Immersion

+

Prepare to focus on the video content

+

Minimum viewing time: ${minDuration} seconds

+ ${tags.length > 0 ? '

Filtering by tags: ' + tags.map(t => '' + t + '').join(' ') + '

' : ''} +
+
+ + +
+ +
+
+ `; + + const btn = container.querySelector('#start-video-player-btn'); + const skipBtn = container.querySelector('#skip-video-btn'); + const statusArea = container.querySelector('#video-start-status'); + const videoContainer = container.querySelector('#video-player-container'); + const timerDisplay = container.querySelector('#video-timer-display'); + + let availableVideos = []; + + const playRandomVideo = async () => { + if (availableVideos.length === 0) return; + + const randomVideo = availableVideos[Math.floor(Math.random() * availableVideos.length)]; + await window.videoPlayerManager.playTaskVideo(randomVideo, videoContainer); + }; + + skipBtn.addEventListener('click', async () => { + if (availableVideos.length > 0) { + await playRandomVideo(); + statusArea.innerHTML = '
⏭️ Skipped to new video
'; + } + }); + + btn.addEventListener('click', async () => { + btn.disabled = true; + btn.textContent = 'Loading...'; + + if (!window.videoPlayerManager) { + statusArea.innerHTML = '
⚠️ Video manager not initialized
'; + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + return; + } + + try { + // Check if videos are available + availableVideos = window.videoPlayerManager.videoLibrary?.background || []; + console.log(`📹 Videos available: ${availableVideos.length}`); + + if (availableVideos.length === 0) { + statusArea.innerHTML = '
ℹ️ No videos in library - continuing anyway
'; + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + return; + } + + await playRandomVideo(); + + btn.style.display = 'none'; + skipBtn.style.display = 'inline-block'; + timerDisplay.style.display = 'block'; + + // Start countdown timer + let remainingTime = minDuration; + timerDisplay.innerHTML = `⏱️ Keep watching... ${remainingTime}s remaining`; + + const timerInterval = setInterval(() => { + remainingTime--; + + if (remainingTime > 0) { + timerDisplay.innerHTML = `⏱️ Keep watching... ${remainingTime}s remaining`; + } else { + clearInterval(timerInterval); + timerDisplay.innerHTML = '✅ Minimum viewing time complete!'; + timerDisplay.style.color = 'var(--color-success, #4caf50)'; + + statusArea.innerHTML = '
✅ You may now continue when ready
'; + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }, 1000); + + } catch (error) { + console.error('Video start error:', error); + statusArea.innerHTML = `
⚠️ ${error.message} - Continuing anyway
`; + // Auto-complete even on error + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }); + } + + validateVideoStartTask(task) { + return task.completed === true; + } + + /** + * Update Preferences Task - Show preference update modal at checkpoint + */ + async createUpdatePreferencesTask(task, container) { + const checkpoint = task.params?.checkpoint || 1; + + container.innerHTML = ` +
+

⚙️ Checkpoint ${checkpoint} - Update Preferences

+

Update your content preferences to personalize future training sessions.

+
+ + +
+
+
+ `; + + const openBtn = container.querySelector('#open-preferences-btn'); + const skipBtn = container.querySelector('#skip-preferences-btn'); + const statusArea = container.querySelector('#preference-status'); + + const completeTask = (message) => { + statusArea.innerHTML = `
${message}
`; + task.completed = true; + if (openBtn) openBtn.disabled = true; + if (skipBtn) skipBtn.disabled = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + }; + + skipBtn.addEventListener('click', () => { + completeTask('✅ Preferences skipped - using current settings'); + }); + + openBtn.addEventListener('click', () => { + if (window.academyUI && window.preferenceManager) { + try { + // Show checkpoint modal with preferences tab active + window.academyUI.showCheckpointModal(checkpoint, () => { + completeTask('✅ Preferences updated'); + }); + } catch (error) { + console.error('Preference editor error:', error); + completeTask('✅ Preferences configured (with errors)'); + } + } else { + // Auto-complete if UI not available + completeTask('✅ Preferences configured (UI unavailable)'); + } + }); + } + + validateUpdatePreferencesTask(task) { + return task.completed === true; + } + + /** + * Free Edge Session Task - Free-form edging with features enabled + */ + async createFreeEdgeSessionTask(task, container) { + const duration = task.params?.duration || 600; + const allowedFeatures = task.params?.allowedFeatures || ['video']; + + let timeRemaining = duration; + let edgeCount = 0; + + container.innerHTML = ` +
+

🎯 Free Edge Session

+

Edge as much as you can with these features enabled:

+
+ ${allowedFeatures.map(f => `${f}`).join(' ')} +
+
+
+ 0 + Edges +
+
+ ${Math.floor(timeRemaining / 60)}:${String(timeRemaining % 60).padStart(2, '0')} + Time Remaining +
+
+ + +
+ `; + + const startBtn = container.querySelector('#start-session-btn'); + const edgeBtn = container.querySelector('#log-edge-btn'); + const edgeCountEl = container.querySelector('#edge-count'); + const timeRemainingEl = container.querySelector('#time-remaining'); + + edgeBtn.disabled = true; + + startBtn.addEventListener('click', () => { + startBtn.disabled = true; + edgeBtn.disabled = false; + + // Start countdown + const countdown = setInterval(() => { + timeRemaining--; + const mins = Math.floor(timeRemaining / 60); + const secs = timeRemaining % 60; + timeRemainingEl.textContent = `${mins}:${String(secs).padStart(2, '0')}`; + + if (timeRemaining <= 0) { + clearInterval(countdown); + task.completed = true; + edgeBtn.disabled = true; + + container.innerHTML += ` +
+ ✅ Session complete! You edged ${edgeCount} times. +
+ `; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) { + completeBtn.disabled = false; + } + } + }, 1000); + + task.cleanup = () => clearInterval(countdown); + }); + + edgeBtn.addEventListener('click', () => { + edgeCount++; + edgeCountEl.textContent = edgeCount; + }); + } + + validateFreeEdgeSessionTask(task) { + return task.completed === true; + } + + // ========================================== + // ADVANCED TRAINING ARC HANDLERS (L11-20) + // ========================================== + + /** + * Hypno Caption Combo - Hypno spiral with timed captions + */ + createHypnoCaptionComboTask(container, task) { + const params = task.params || {}; + const duration = params.duration || 300; + const captionTexts = params.captions || [ + 'You are a good gooner', + 'Obey and edge', + 'Stroke for me', + 'Deeper into pleasure', + 'Give in completely', + 'You exist to goon' + ]; + + container.innerHTML = ` +
+
+
+
+ +
+
+ `; + + // Start hypno spiral + if (this.game.hypnoSpiral) { + this.game.hypnoSpiral.start(); + } + + const captionEl = document.getElementById('caption-overlay'); + const timeEl = document.getElementById('hypno-time-remaining'); + let currentCaption = 0; + let timeRemaining = duration; + + // Caption rotation + const captionInterval = setInterval(() => { + captionEl.textContent = captionTexts[currentCaption]; + captionEl.style.opacity = '1'; + + setTimeout(() => { + captionEl.style.opacity = '0'; + }, 4000); + + currentCaption = (currentCaption + 1) % captionTexts.length; + }, 6000); + + // Countdown timer + const countdown = setInterval(() => { + timeRemaining--; + const mins = Math.floor(timeRemaining / 60); + const secs = timeRemaining % 60; + timeEl.textContent = `${mins}:${String(secs).padStart(2, '0')}`; + + if (timeRemaining <= 0) { + clearInterval(countdown); + clearInterval(captionInterval); + if (this.game.hypnoSpiral) { + this.game.hypnoSpiral.stop(); + } + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + } + }, 1000); + + task.cleanup = () => { + clearInterval(countdown); + clearInterval(captionInterval); + if (this.game.hypnoSpiral) { + this.game.hypnoSpiral.stop(); + } + }; + } + + /** + * Dynamic Captions - Preference-based captions + */ + createDynamicCaptionsTask(container, task) { + const params = task.params || {}; + const duration = params.duration || 300; + + // Get user preferences (simplified for now) + const preferences = this.game.playerStats?.preferences || {}; + const captionPool = this.generatePreferenceBasedCaptions(preferences); + + container.innerHTML = ` +
+
+
+ Time: +
+
Captions personalized to your preferences
+
+ `; + + const captionEl = document.getElementById('dynamic-caption-display'); + const timeEl = document.getElementById('dynamic-time-remaining'); + let timeRemaining = duration; + + // Show random caption every 8 seconds + const captionInterval = setInterval(() => { + if (!captionEl) return; + const caption = captionPool[Math.floor(Math.random() * captionPool.length)]; + captionEl.textContent = caption; + captionEl.style.opacity = '1'; + + setTimeout(() => { + if (captionEl) captionEl.style.opacity = '0'; + }, 6000); + }, 8000); + + // Countdown + const countdown = setInterval(() => { + timeRemaining--; + const mins = Math.floor(timeRemaining / 60); + const secs = timeRemaining % 60; + if (timeEl) timeEl.textContent = `${mins}:${String(secs).padStart(2, '0')}`; + + if (timeRemaining <= 0) { + clearInterval(countdown); + clearInterval(captionInterval); + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + } + }, 1000); + + task.cleanup = () => { + clearInterval(countdown); + clearInterval(captionInterval); + }; + } + + generatePreferenceBasedCaptions(preferences) { + // Default captions if no preferences + return [ + 'You love to edge', + 'Gooning is your purpose', + 'Stroke and obey', + 'Deeper into pleasure', + 'You are addicted', + 'Edge for hours', + 'No thinking, only gooning', + 'You need this', + 'Pump and goon', + 'Surrender completely' + ]; + } + + /** + * TTS Hypno Sync - Voice + hypno synchronized + */ + createTTSHypnoSyncTask(container, task) { + const params = task.params || {}; + const duration = params.duration || 300; + const commands = params.commands || [ + 'Focus on the spiral', + 'Let your mind go blank', + 'Stroke slowly and deeply', + 'You are under my control', + 'Obey and edge' + ]; + + container.innerHTML = ` +
+
+
+
+ Time: +
+
+ `; + + // Start hypno + if (this.game.hypnoSpiral) { + this.game.hypnoSpiral.start(); + } + + const commandEl = document.getElementById('tts-command-display'); + const timeEl = document.getElementById('tts-time-remaining'); + let timeRemaining = duration; + let commandIndex = 0; + + // Speak commands every 30 seconds + const speakCommand = () => { + const command = commands[commandIndex]; + commandEl.textContent = command; + + if (this.voiceManager && this.ttsEnabled) { + this.voiceManager.speak(command); + } + + commandIndex = (commandIndex + 1) % commands.length; + }; + + speakCommand(); // First command immediately + const commandInterval = setInterval(speakCommand, 30000); + + // Countdown + const countdown = setInterval(() => { + timeRemaining--; + const mins = Math.floor(timeRemaining / 60); + const secs = timeRemaining % 60; + timeEl.textContent = `${mins}:${String(secs).padStart(2, '0')}`; + + if (timeRemaining <= 0) { + clearInterval(countdown); + clearInterval(commandInterval); + if (this.game.hypnoSpiral) { + this.game.hypnoSpiral.stop(); + } + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + } + }, 1000); + + task.cleanup = () => { + clearInterval(countdown); + clearInterval(commandInterval); + if (this.game.hypnoSpiral) { + this.game.hypnoSpiral.stop(); + } + }; + } + + /** + * Sensory Overload - All features combined + */ + createSensoryOverloadTask(container, task) { + const params = task.params || {}; + const duration = params.duration || 600; + const edgeTarget = params.edgeCount || 50; + + container.innerHTML = ` +
+
+
+
+
Edges: 0 / ${edgeTarget}
+
Time:
+
+ +
⚠️ ALL FEATURES ACTIVE ⚠️
+
+ `; + + // Start ALL features + if (this.game.hypnoSpiral) { + this.game.hypnoSpiral.start(); + } + + const captionEl = document.getElementById('overload-caption'); + const edgeCountEl = document.getElementById('overload-edge-count'); + const timeEl = document.getElementById('overload-time-remaining'); + const edgeBtn = document.getElementById('overload-edge-btn'); + + let edgeCount = 0; + let timeRemaining = duration; + + const captions = [ + 'EDGE NOW', 'OBEY', 'GOON HARDER', 'SUBMIT', 'EDGE AGAIN', + 'YOU ARE MINE', 'STROKE', 'PUMP', 'DEEPER', 'MORE' + ]; + + // Rapid caption rotation + const captionInterval = setInterval(() => { + if (captionEl) captionEl.textContent = captions[Math.floor(Math.random() * captions.length)]; + }, 3000); + + // TTS commands + const ttsCommands = ['Edge now', 'Faster', 'Slower', 'Stop', 'Continue']; + const ttsInterval = setInterval(() => { + if (this.voiceManager && this.ttsEnabled) { + const cmd = ttsCommands[Math.floor(Math.random() * ttsCommands.length)]; + this.voiceManager.speak(cmd); + } + }, 25000); + + // Countdown + const countdown = setInterval(() => { + timeRemaining--; + const mins = Math.floor(timeRemaining / 60); + const secs = timeRemaining % 60; + if (timeEl) timeEl.textContent = `${mins}:${String(secs).padStart(2, '0')}`; + + if (timeRemaining <= 0) { + clearInterval(countdown); + clearInterval(captionInterval); + clearInterval(ttsInterval); + if (this.game.hypnoSpiral) { + this.game.hypnoSpiral.stop(); + } + task.completed = true; + if (edgeBtn) edgeBtn.disabled = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + } + }, 1000); + + if (edgeBtn) { + edgeBtn.addEventListener('click', () => { + edgeCount++; + if (edgeCountEl) edgeCountEl.textContent = edgeCount; + }); + } + + task.cleanup = () => { + clearInterval(countdown); + clearInterval(captionInterval); + clearInterval(ttsInterval); + if (this.game.hypnoSpiral) { + this.game.hypnoSpiral.stop(); + } + }; + } + + /** + * Enable Interruptions - Activate interruption system + */ + createEnableInterruptionsTask(container, task) { + const params = task.params || {}; + const types = params.types || ['edge', 'pose', 'mantra', 'stop-stroking']; + const frequency = params.frequency || 'medium'; + + container.innerHTML = ` +
+
+

🚨 INTERRUPTIONS ACTIVATED 🚨

+

Random commands will interrupt your sessions:

+
    + ${types.map(type => `
  • ${type}
  • `).join('')} +
+

Frequency: ${frequency}

+

You must obey immediately when interrupted.

+
+ +
+ `; + + const acceptBtn = document.getElementById('accept-interruptions-btn'); + acceptBtn.addEventListener('click', () => { + // Store interruption settings in game state + if (!this.game.interruptionSettings) { + this.game.interruptionSettings = {}; + } + this.game.interruptionSettings.enabled = true; + this.game.interruptionSettings.types = types; + this.game.interruptionSettings.frequency = frequency; + + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + }); + } + + /** + * Denial Training - Timed stroking/stopping periods + */ + createDenialTrainingTask(container, task) { + const params = task.params || {}; + const periods = params.denialPeriods || [ + { allowStroking: 300, instruction: 'Stroke for 5 minutes' }, + { stopDuration: 120, instruction: 'HANDS OFF for 2 minutes' } + ]; + + let currentPeriod = 0; + let timeInPeriod = 0; + + const updateDisplay = () => { + const period = periods[currentPeriod]; + const isStroking = period.hasOwnProperty('allowStroking'); + const duration = isStroking ? period.allowStroking : period.stopDuration; + const remaining = duration - timeInPeriod; + + container.innerHTML = ` +
+

${isStroking ? '✋ STROKE' : '🚫 STOP - HANDS OFF'}

+
${period.instruction}
+
+ ${Math.floor(remaining / 60)}:${String(remaining % 60).padStart(2, '0')} +
+
+ Period ${currentPeriod + 1} of ${periods.length} +
+
+ `; + }; + + updateDisplay(); + + const interval = setInterval(() => { + timeInPeriod++; + const period = periods[currentPeriod]; + const duration = period.hasOwnProperty('allowStroking') ? period.allowStroking : period.stopDuration; + + if (timeInPeriod >= duration) { + currentPeriod++; + timeInPeriod = 0; + + if (currentPeriod >= periods.length) { + clearInterval(interval); + task.completed = true; + + container.innerHTML = ` +
+

✅ Denial Training Complete

+

You have learned discipline through denial.

+
+ `; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + return; + } + } + + updateDisplay(); + }, 1000); + + task.cleanup = () => clearInterval(interval); + } + + /** + * Stop Stroking - Enforced hands-off period + */ + createStopStrokingTask(container, task) { + const params = task.params || {}; + const duration = params.duration || 120; + + container.innerHTML = ` +
+

🚫 STOP STROKING 🚫

+
HANDS OFF. NO TOUCHING.
+
+
You must wait the full duration.
+
+ `; + + const timerEl = document.getElementById('stop-timer'); + let timeRemaining = duration; + + const countdown = setInterval(() => { + timeRemaining--; + const mins = Math.floor(timeRemaining / 60); + const secs = timeRemaining % 60; + timerEl.textContent = `${mins}:${String(secs).padStart(2, '0')}`; + + if (timeRemaining <= 0) { + clearInterval(countdown); + task.completed = true; + + container.innerHTML = ` +
+

✅ Denial Period Complete

+

You may resume stroking.

+
+ `; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + } + }, 1000); + + task.cleanup = () => clearInterval(countdown); + } + + /** + * Enable Popups - Activate popup system + */ + createEnablePopupsTask(container, task) { + const params = task.params || {}; + const frequency = params.frequency || 'medium'; + const sources = params.sources || ['tasks', 'consequences']; + + container.innerHTML = ` +
+
+

📸 POPUP SYSTEM ACTIVATED 📸

+

Random images will appear during your sessions:

+
    + ${sources.map(src => `
  • ${src}
  • `).join('')} +
+

Frequency: ${frequency}

+

You must read and acknowledge each popup.

+
+ +
+ `; + + const acceptBtn = document.getElementById('accept-popups-btn'); + acceptBtn.addEventListener('click', () => { + // Store popup settings in game state + if (!this.game.popupSettings) { + this.game.popupSettings = {}; + } + this.game.popupSettings.enabled = true; + this.game.popupSettings.sources = sources; + this.game.popupSettings.frequency = frequency; + + task.completed = true; + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + }); + } + + /** + * Popup Image - Display specific popup + */ + createPopupImageTask(container, task) { + const params = task.params || {}; + const imagePath = params.image || ''; + const displayTime = params.duration || 10; + const message = params.message || 'Acknowledge this popup'; + + container.innerHTML = ` + + `; + + const timerEl = document.getElementById('popup-timer'); + const ackBtn = document.getElementById('popup-acknowledge-btn'); + let timeRemaining = displayTime; + + const countdown = setInterval(() => { + timeRemaining--; + timerEl.textContent = timeRemaining; + + if (timeRemaining <= 0) { + clearInterval(countdown); + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + } + }, 1000); + + ackBtn.addEventListener('click', () => { + clearInterval(countdown); + task.completed = true; + + const completeBtn = document.getElementById('interactive-complete-btn'); + if (completeBtn) completeBtn.disabled = false; + }); + + task.cleanup = () => clearInterval(countdown); + } + + /** + * Generic validators for timed tasks + */ + validateTimedTask(task) { + return task.completed === true; + } + + validateInstantTask(task) { + return task.completed === true; + } + /** * Clean up quad video player and other resources */ diff --git a/src/features/video/videoPlayerManager.js b/src/features/video/videoPlayerManager.js index ceecb2e..b6ad9f5 100644 --- a/src/features/video/videoPlayerManager.js +++ b/src/features/video/videoPlayerManager.js @@ -366,12 +366,22 @@ class VideoPlayerManager { } /** - * Get full video path + * Get full path for video */ getVideoPath(videoPath) { - if (videoPath.startsWith('http') || videoPath.startsWith('file:') || videoPath.startsWith('video/')) { + // Already a full URL + if (videoPath.startsWith('http') || videoPath.startsWith('file:')) { return videoPath; } + + // Absolute path (Windows: C:\... or E:\..., Unix: /...) + if (videoPath.match(/^[A-Z]:\\/i) || videoPath.startsWith('/')) { + // Convert to file:// URL for Electron + const normalizedPath = videoPath.replace(/\\/g, '/'); + return `file:///${normalizedPath}`; + } + + // Relative path - add video/ prefix return `video/${videoPath}`; } diff --git a/src/features/webcam/webcamManager.js b/src/features/webcam/webcamManager.js index ce56705..0ad8a72 100644 --- a/src/features/webcam/webcamManager.js +++ b/src/features/webcam/webcamManager.js @@ -213,29 +213,19 @@ class WebcamManager { this.savePhotoData(photoData); // Check if session is complete + console.log(`📊 Checking completion: ${photosTaken} >= ${photosNeeded}?`, photosTaken >= photosNeeded); if (photosTaken >= photosNeeded) { - // For single-photo sessions (like Quick Play), auto-complete - if (photosNeeded === 1) { - console.log(`✅ Single-photo session complete! Auto-completing...`); - // Small delay to let user see the completion message - setTimeout(() => { - this.completePhotoSession(); - }, 1000); - } else { - // Show completion button for multi-photo sessions - document.getElementById('complete-session').style.display = 'inline-block'; - document.getElementById('capture-photo').style.display = 'none'; - document.getElementById('accept-photo').style.display = 'none'; - - // Update header - document.querySelector('.session-instruction').textContent = '🎉 Session complete! All photos taken.'; - - console.log(`✅ Photo session complete! ${photosTaken}/${photosNeeded} photos taken`); - } + console.log(`✅ Photo session complete! ${photosTaken}/${photosNeeded} photos taken - auto-completing in 1 second...`); + + // Auto-complete session when required photos are captured + setTimeout(() => { + console.log('⏰ Timeout fired - calling completePhotoSession()'); + this.completePhotoSession(); + }, 1000); } else { // Return to camera view for more photos this.showCameraPreview(); - console.log(`📸 Photo accepted (${photosTaken}/${photosNeeded})`); + console.log(`📸 Photo accepted (${photosTaken}/${photosNeeded}) - continuing session`); } } @@ -244,10 +234,17 @@ class WebcamManager { */ completePhotoSession() { console.log('🎉 Photo session completed successfully'); + console.log('📊 Current session:', this.currentPhotoSession); - // Show photo gallery before completing - this.showPhotoGallery(() => { - // Notify task completion after gallery is closed + // For single-photo sessions (like progression challenges), skip gallery + const isSinglePhotoSession = this.currentPhotoSession.photosNeeded === 1; + console.log(`🔍 Single-photo session? ${isSinglePhotoSession} (photosNeeded: ${this.currentPhotoSession.photosNeeded})`); + + if (isSinglePhotoSession) { + console.log('📸 Single-photo session - skipping gallery, ending immediately'); + + // Notify task completion immediately + console.log('🔔 Dispatching photoSessionComplete event...'); const event = new CustomEvent('photoSessionComplete', { detail: { photos: this.currentPhotoSession.photos, @@ -256,10 +253,31 @@ class WebcamManager { } }); document.dispatchEvent(event); + console.log('✅ Event dispatched'); // End session + console.log('🔚 Calling endPhotoSession()...'); this.endPhotoSession(); - }); + console.log('✅ endPhotoSession() completed'); + } else { + console.log('📸 Multi-photo session - showing gallery first'); + // Show photo gallery for multi-photo sessions before completing + this.showPhotoGallery(() => { + console.log('📸 Gallery closed - dispatching event and ending session'); + // Notify task completion after gallery is closed + const event = new CustomEvent('photoSessionComplete', { + detail: { + photos: this.currentPhotoSession.photos, + sessionType: this.currentPhotoSession.type, + taskData: this.currentPhotoSession.taskData + } + }); + document.dispatchEvent(event); + + // End session + this.endPhotoSession(); + }); + } } /** @@ -686,7 +704,7 @@ class WebcamManager { /** * Save photo data (respecting privacy) */ - savePhotoData(photoData) { + async savePhotoData(photoData) { // Save metadata to session storage (temporary) const metadata = { timestamp: photoData.timestamp, @@ -698,8 +716,36 @@ class WebcamManager { sessionPhotos.push(metadata); sessionStorage.setItem('photoSession', JSON.stringify(sessionPhotos)); - // Save actual photo data to localStorage with user consent - this.savePersistentPhoto(photoData); + // Save actual photo to file system if running in Electron + if (this.game && this.game.fileManager && this.game.fileManager.isElectron) { + await this.savePhotoToFileSystem(photoData); + } else { + // Browser mode - save to localStorage with user consent + this.savePersistentPhoto(photoData); + } + } + + /** + * Save photo to file system (Electron only) + */ + async savePhotoToFileSystem(photoData) { + try { + const savedPhoto = await this.game.fileManager.savePhoto( + photoData.dataURL, + photoData.sessionType + ); + + if (savedPhoto) { + console.log(`📸 Photo saved to file system: ${savedPhoto.filename}`); + this.showNotification('📸 Photo saved to file system!', 'success'); + } else { + console.warn('📸 Failed to save photo to file system'); + this.showNotification('⚠️ Failed to save photo', 'warning'); + } + } catch (error) { + console.error('📸 Error saving photo to file system:', error); + this.showNotification('⚠️ Failed to save photo', 'warning'); + } } /** @@ -1094,12 +1140,19 @@ class WebcamManager { // Remove camera overlay const overlay = document.getElementById('camera-overlay'); + console.log('🔍 Camera overlay element:', overlay); if (overlay) { + console.log('🗑️ Removing camera overlay...'); overlay.remove(); + console.log('✅ Camera overlay removed'); + } else { + console.log('⚠️ No camera overlay found to remove'); } // Stop camera stream + console.log('📹 Stopping camera stream...'); this.stopCamera(); + console.log('✅ Camera stream stopped'); // Clear current session if (this.currentPhotoSession) { diff --git a/src/styles/academy-ui.css b/src/styles/academy-ui.css new file mode 100644 index 0000000..6bb4282 --- /dev/null +++ b/src/styles/academy-ui.css @@ -0,0 +1,1271 @@ +/* Academy UI Styles */ + +/* Level Select Screen */ +.level-select-screen { + padding: 20px; + max-width: 1400px; + margin: 0 auto; +} + +.level-select-header { + text-align: center; + margin-bottom: 30px; +} + +.level-select-header h2 { + color: #ff006e; + font-size: 2.5em; + margin-bottom: 10px; +} + +.progress-subtitle { + color: #aaa; + font-size: 1.1em; + margin-bottom: 20px; +} + +.campaign-progress { + max-width: 600px; + margin: 0 auto; +} + +.progress-bar-container { + width: 100%; + height: 25px; + background: #2a2a2a; + border-radius: 12px; + overflow: hidden; + border: 2px solid #ff006e; + margin-bottom: 10px; +} + +.progress-bar-fill { + height: 100%; + background: linear-gradient(90deg, #ff006e, #8338ec); + transition: width 0.5s ease; +} + +.progress-text { + color: #e0e0e0; + font-weight: bold; + font-size: 1.1em; +} + +/* Level Grid */ +.level-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); + gap: 15px; + margin-bottom: 30px; +} + +.level-button { + position: relative; + background: #2a2a2a; + border: 2px solid #444; + border-radius: 12px; + padding: 15px; + cursor: pointer; + transition: all 0.3s ease; + min-height: 120px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 10px; +} + +.level-button:hover:not(:disabled) { + border-color: #ff006e; + box-shadow: 0 0 20px rgba(255, 0, 110, 0.3); + transform: translateY(-2px); +} + +.level-button.unlocked { + border-color: #00ff88; + background: linear-gradient(135deg, #2a2a2a, #1a3a2a); +} + +.level-button.completed { + border-color: #8338ec; + background: linear-gradient(135deg, #2a2a2a, #2a1a3a); +} + +.level-button.current { + border-color: #ff006e; + box-shadow: 0 0 30px rgba(255, 0, 110, 0.5); + animation: pulse 2s infinite; +} + +.level-button:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.level-number { + font-size: 2em; + font-weight: bold; + color: #e0e0e0; +} + +.level-icon { + font-size: 1.5em; +} + +.checkpoint-badge { + position: absolute; + top: 5px; + right: 5px; + background: #ffb700; + color: #000; + padding: 2px 6px; + border-radius: 4px; + font-size: 0.8em; +} + +@keyframes pulse { + 0%, 100% { + box-shadow: 0 0 30px rgba(255, 0, 110, 0.5); + } + 50% { + box-shadow: 0 0 50px rgba(255, 0, 110, 0.8); + } +} + +/* Level Info Panel */ +.level-info-panel { + background: #2a2a2a; + border: 2px solid #444; + border-radius: 12px; + padding: 20px; + margin-bottom: 20px; + min-height: 200px; +} + +.info-hint { + color: #888; + text-align: center; + font-style: italic; + padding: 80px 0; +} + +.level-details h3 { + color: #ff006e; + font-size: 1.8em; + margin-bottom: 15px; +} + +.level-meta { + display: flex; + gap: 10px; + margin-bottom: 15px; + flex-wrap: wrap; +} + +.arc-badge, .checkpoint-badge-large, .completed-badge { + padding: 5px 12px; + border-radius: 6px; + font-size: 0.9em; + font-weight: bold; +} + +.arc-badge { + background: rgba(131, 56, 236, 0.3); + color: #8338ec; + border: 1px solid #8338ec; +} + +.checkpoint-badge-large { + background: rgba(255, 183, 0, 0.3); + color: #ffb700; + border: 1px solid #ffb700; +} + +.completed-badge { + background: rgba(0, 255, 136, 0.3); + color: #00ff88; + border: 1px solid #00ff88; +} + +.level-description { + color: #ccc; + font-size: 1.1em; + margin-bottom: 15px; + line-height: 1.6; +} + +.checkpoint-notice { + background: rgba(255, 183, 0, 0.1); + border-left: 3px solid #ffb700; + padding: 10px 15px; + border-radius: 6px; + color: #ffb700; + margin-bottom: 15px; +} + +.btn-start-level { + background: linear-gradient(135deg, #ff006e, #8338ec); + color: white; + border: none; + padding: 12px 30px; + border-radius: 8px; + font-size: 1.1em; + font-weight: bold; + cursor: pointer; + transition: transform 0.2s; +} + +.btn-start-level:hover { + transform: translateY(-2px); + box-shadow: 0 5px 20px rgba(255, 0, 110, 0.5); +} + +.level-select-footer { + text-align: center; + padding: 20px 0; +} + +.btn-back { + background: #444; + color: white; + border: 1px solid #666; + padding: 10px 25px; + border-radius: 8px; + cursor: pointer; + transition: all 0.3s; +} + +.btn-back:hover { + background: #555; + border-color: #888; +} + +/* Checkpoint Modal */ +.checkpoint-modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.9); + z-index: 10000; + display: flex; + align-items: center; + justify-content: center; + backdrop-filter: blur(10px); +} + +.checkpoint-modal { + background: #1a1a1a; + border: 2px solid #ff006e; + border-radius: 15px; + max-width: 900px; + width: 90%; + max-height: 90vh; + overflow-y: auto; + box-shadow: 0 10px 50px rgba(255, 0, 110, 0.5); +} + +.checkpoint-header { + padding: 25px; + border-bottom: 2px solid #333; + text-align: center; +} + +.checkpoint-header h2 { + color: #ff006e; + font-size: 2em; + margin-bottom: 10px; +} + +.checkpoint-header p { + color: #aaa; + font-size: 1.1em; +} + +/* Tabs */ +.checkpoint-tabs { + display: flex; + border-bottom: 2px solid #333; +} + +.tab-btn { + flex: 1; + padding: 15px; + background: transparent; + border: none; + color: #888; + cursor: pointer; + font-size: 1.1em; + transition: all 0.3s; + border-bottom: 3px solid transparent; +} + +.tab-btn:hover { + color: #ccc; + background: rgba(255, 255, 255, 0.05); +} + +.tab-btn.active { + color: #ff006e; + border-bottom-color: #ff006e; +} + +/* Tab Panels */ +.checkpoint-content { + padding: 25px; + min-height: 400px; +} + +.tab-panel { + display: none; +} + +.tab-panel.active { + display: block; +} + +/* Preferences Editor */ +.pref-category { + margin-bottom: 30px; + background: #2a2a2a; + padding: 20px; + border-radius: 10px; +} + +.pref-category h3 { + color: #8338ec; + margin-bottom: 15px; + font-size: 1.3em; +} + +.checkbox-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + gap: 12px; +} + +.checkbox-label { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + background: #1a1a1a; + border-radius: 6px; + cursor: pointer; + transition: background 0.2s; +} + +.checkbox-label:hover { + background: rgba(255, 0, 110, 0.1); +} + +.checkbox-label input[type="checkbox"] { + cursor: pointer; + width: 18px; + height: 18px; +} + +.slider-group { + margin-bottom: 20px; + background: #1a1a1a; + padding: 15px; + border-radius: 6px; +} + +.slider-group label { + display: block; + color: #e0e0e0; + margin-bottom: 8px; + font-weight: bold; +} + +.slider-group input[type="range"] { + width: 100%; + height: 6px; + border-radius: 3px; + background: #444; + outline: none; + cursor: pointer; +} + +.slider-group input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 20px; + height: 20px; + border-radius: 50%; + background: #ff006e; + cursor: pointer; +} + +.slider-group input[type="range"]::-moz-range-thumb { + width: 20px; + height: 20px; + border-radius: 50%; + background: #ff006e; + cursor: pointer; + border: none; +} + +/* Library Manager */ +.library-stats { + background: #2a2a2a; + padding: 20px; + border-radius: 10px; +} + +.library-stats h3 { + color: #ff006e; + margin-bottom: 20px; + font-size: 1.3em; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 15px; + margin-bottom: 20px; +} + +.stat-item { + background: #1a1a1a; + padding: 15px; + border-radius: 8px; + text-align: center; +} + +.stat-label { + display: block; + color: #888; + font-size: 0.9em; + margin-bottom: 5px; +} + +.stat-value { + display: block; + color: #00ff88; + font-size: 1.5em; + font-weight: bold; +} + +.library-hint { + color: #888; + font-style: italic; + text-align: center; + padding: 15px; + background: rgba(255, 183, 0, 0.05); + border-radius: 6px; +} + +/* Modal Footer */ +.checkpoint-footer { + padding: 20px 25px; + border-top: 2px solid #333; + display: flex; + justify-content: space-between; + gap: 15px; +} + +.btn-primary, .btn-secondary { + padding: 12px 30px; + border-radius: 8px; + font-size: 1.1em; + font-weight: bold; + cursor: pointer; + border: none; + transition: all 0.3s; +} + +.btn-primary { + background: linear-gradient(135deg, #ff006e, #8338ec); + color: white; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 5px 20px rgba(255, 0, 110, 0.5); +} + +.btn-secondary { + background: #444; + color: white; + border: 1px solid #666; +} + +.btn-secondary:hover { + background: #555; + border-color: #888; +} + +/* ======================================== + ACADEMY TRAINING TASK STYLES + ======================================== */ + +/* Edge Training Task */ +.academy-edge-task { + padding: 20px; + text-align: center; +} + +.academy-edge-task h3 { + color: #ff006e; + margin-bottom: 15px; +} + +.academy-edge-task .instruction { + font-size: 1.2em; + margin-bottom: 20px; + color: #e0e0e0; +} + +.edge-counter { + margin: 30px auto; + max-width: 300px; +} + +.counter-display { + font-size: 3em; + font-weight: bold; + color: #ff006e; + margin-bottom: 15px; +} + +.counter-display .separator { + color: #666; + margin: 0 10px; +} + +.progress-bar { + width: 100%; + height: 30px; + background: #2a2a2a; + border-radius: 15px; + overflow: hidden; + border: 2px solid #ff006e; +} + +.progress-fill { + height: 100%; + background: linear-gradient(90deg, #ff006e, #8338ec); + transition: width 0.5s ease; +} + +.btn-edge { + padding: 15px 40px; + font-size: 1.3em; + margin-top: 20px; +} + +/* Rhythm Pattern Task */ +.academy-rhythm-task { + padding: 20px; + text-align: center; +} + +.academy-rhythm-task h3 { + color: #8338ec; + margin-bottom: 20px; +} + +.rhythm-display { + margin: 30px auto; + max-width: 400px; +} + +.metronome-visual { + width: 150px; + height: 150px; + margin: 0 auto 20px; + background: #2a2a2a; + border: 3px solid #8338ec; + border-radius: 50%; + transition: all 0.1s; +} + +.metronome-visual.beat { + background: #8338ec; + transform: scale(1.1); + box-shadow: 0 0 30px rgba(131, 56, 236, 0.8); +} + +.bpm-display { + font-size: 2em; + color: #8338ec; + margin-bottom: 10px; +} + +.phase-indicator { + color: #aaa; + font-size: 1.1em; +} + +.timer-display { + font-size: 1.5em; + color: #e0e0e0; + margin-top: 20px; +} + +/* Library Tasks */ +.academy-library-task, .academy-tag-task { + padding: 20px; +} + +.academy-library-task h3, .academy-tag-task h3 { + color: #00ff88; + margin-bottom: 15px; +} + +.suggestion { + background: rgba(0, 255, 136, 0.1); + padding: 10px; + border-radius: 6px; + margin: 10px 0; +} + +.tag { + display: inline-block; + background: #00ff88; + color: #000; + padding: 3px 10px; + border-radius: 12px; + font-size: 0.9em; + margin: 2px; +} + +.result-area, .status-area { + margin-top: 20px; + padding: 15px; + border-radius: 6px; +} + +.success { + background: rgba(0, 255, 136, 0.2); + color: #00ff88; + border: 1px solid #00ff88; +} + +.error { + background: rgba(255, 0, 110, 0.2); + color: #ff006e; + border: 1px solid #ff006e; +} + +.tag-progress { + font-size: 1.5em; + color: #00ff88; + margin: 20px 0; +} + +/* Webcam Task */ +.academy-webcam-task { + padding: 20px; + text-align: center; +} + +.academy-webcam-task h3 { + color: #ffb700; + margin-bottom: 15px; +} + +.webcam-preview { + margin-top: 20px; + min-height: 60px; +} + +/* Video Tasks */ +.academy-dual-video-task, .academy-quad-video-task { + padding: 20px; + text-align: center; +} + +.academy-dual-video-task h3 { + color: #ff006e; + margin-bottom: 15px; +} + +.academy-quad-video-task h3 { + color: #8338ec; + margin-bottom: 15px; +} + +/* TTS Task */ +.academy-tts-task { + padding: 20px; + text-align: center; +} + +.academy-tts-task h3 { + color: #00d9ff; + margin-bottom: 15px; +} + +.tts-message { + font-size: 1.3em; + font-style: italic; + color: #e0e0e0; + margin: 20px 0; + padding: 15px; + background: rgba(0, 217, 255, 0.1); + border-left: 4px solid #00d9ff; + border-radius: 6px; +} + +/* Hypno Spiral Task */ +.academy-hypno-task { + padding: 20px; + text-align: center; +} + +.academy-hypno-task h3 { + color: #ff00ff; + margin-bottom: 15px; +} + +.hypno-container { + margin: 30px auto; + max-width: 400px; +} + +.spiral-animation { + width: 300px; + height: 300px; + margin: 0 auto; + background: radial-gradient(circle, #ff00ff 0%, #8338ec 25%, #000 50%); + border-radius: 50%; + border: 3px solid #ff00ff; +} + +.spiral-animation.spinning { + animation: spin 3s linear infinite; +} + +@keyframes spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +.success-message { + background: rgba(0, 255, 136, 0.2); + color: #00ff88; + padding: 15px; + border-radius: 6px; + margin-top: 20px; + font-size: 1.2em; + border: 2px solid #00ff88; +} + +/* Video Start Task */ +.academy-video-start-task { + padding: 20px; + text-align: center; +} + +.academy-video-start-task h3 { + color: #ff006e; + margin-bottom: 15px; +} + +/* Update Preferences Task */ +.academy-update-preferences-task { + padding: 20px; + text-align: center; +} + +.academy-update-preferences-task h3 { + color: #ffb700; + margin-bottom: 15px; +} + +/* Free Edge Session Task */ +.academy-free-edge-task { + padding: 20px; + text-align: center; +} + +.academy-free-edge-task h3 { + color: #8338ec; + margin-bottom: 15px; +} + +.feature-list { + margin: 20px 0; +} + +.feature-badge { + display: inline-block; + background: linear-gradient(135deg, #ff006e, #8338ec); + color: white; + padding: 8px 15px; + border-radius: 20px; + font-weight: bold; + margin: 5px; + font-size: 0.9em; +} + +.session-stats { + display: flex; + justify-content: center; + gap: 40px; + margin: 30px 0; +} + +.stat { + display: flex; + flex-direction: column; + align-items: center; +} + +.stat-value { + font-size: 3em; + font-weight: bold; + color: #8338ec; +} + +.stat-label { + font-size: 1.1em; + color: #aaa; + margin-top: 5px; +} + +#log-edge-btn { + margin: 10px; + padding: 12px 30px; + font-size: 1.2em; +} + +/* ========================================== + ADVANCED TRAINING ARC STYLES (L11-20) + ========================================== */ + +/* Hypno Caption Combo */ +.hypno-caption-container { + position: relative; + width: 100%; + height: 600px; + background: #000; + border-radius: 12px; + overflow: hidden; +} + +.hypno-spiral-background { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: radial-gradient(circle, #8338ec, #000); + animation: spiral-rotate 10s linear infinite; +} + +@keyframes spiral-rotate { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +.caption-overlay { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 2.5em; + font-weight: bold; + color: #fff; + text-shadow: 0 0 20px #ff006e, 0 0 40px #ff006e; + opacity: 0; + transition: opacity 1s ease; + text-align: center; + padding: 20px; + z-index: 10; +} + +/* Dynamic Captions */ +.dynamic-captions-container { + padding: 40px; + text-align: center; +} + +.dynamic-caption { + font-size: 3em; + font-weight: bold; + color: #ff006e; + text-shadow: 0 0 30px #ff006e; + min-height: 100px; + display: flex; + align-items: center; + justify-content: center; + margin: 40px 0; + opacity: 0; + transition: opacity 0.8s ease; +} + +.caption-info { + color: #aaa; + font-style: italic; + margin-top: 20px; +} + +/* TTS Hypno Sync */ +.tts-hypno-container { + position: relative; + width: 100%; + height: 600px; + background: #000; + border-radius: 12px; + overflow: hidden; +} + +.tts-command { + position: absolute; + bottom: 50px; + left: 50%; + transform: translateX(-50%); + font-size: 2em; + font-weight: bold; + color: #00ff88; + text-shadow: 0 0 20px #00ff88; + background: rgba(0, 0, 0, 0.8); + padding: 20px 40px; + border-radius: 12px; + border: 2px solid #00ff88; + z-index: 10; +} + +/* Sensory Overload */ +.sensory-overload-container { + position: relative; + width: 100%; + min-height: 600px; + background: #000; + border-radius: 12px; + overflow: hidden; + padding: 20px; +} + +.overload-stats { + position: absolute; + top: 20px; + right: 20px; + background: rgba(0, 0, 0, 0.9); + padding: 20px; + border-radius: 12px; + border: 2px solid #ff006e; + font-size: 1.3em; + z-index: 20; +} + +.overload-stats div { + margin: 10px 0; + color: #fff; +} + +.edge-button { + position: absolute; + bottom: 40px; + left: 50%; + transform: translateX(-50%); + padding: 20px 60px; + font-size: 1.8em; + font-weight: bold; + background: linear-gradient(135deg, #ff006e, #8338ec); + border: 3px solid #fff; + border-radius: 20px; + color: #fff; + cursor: pointer; + transition: all 0.3s ease; + z-index: 20; +} + +.edge-button:hover:not(:disabled) { + transform: translateX(-50%) scale(1.1); + box-shadow: 0 0 40px rgba(255, 0, 110, 0.8); +} + +.edge-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.overload-warning { + position: absolute; + top: 20px; + left: 50%; + transform: translateX(-50%); + font-size: 1.5em; + font-weight: bold; + color: #ff006e; + text-shadow: 0 0 20px #ff006e; + animation: warning-pulse 1.5s infinite; + z-index: 20; +} + +@keyframes warning-pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } +} + +/* Enable Interruptions / Popups */ +.enable-interruptions-container, +.enable-popups-container { + padding: 40px; + text-align: center; +} + +.feature-unlock { + background: linear-gradient(135deg, #2a2a2a, #1a1a3a); + border: 3px solid #ff006e; + border-radius: 20px; + padding: 40px; + max-width: 600px; + margin: 0 auto 30px; +} + +.feature-unlock h3 { + color: #ff006e; + font-size: 2em; + margin-bottom: 20px; + text-shadow: 0 0 20px #ff006e; +} + +.feature-unlock p { + font-size: 1.2em; + margin: 15px 0; + color: #e0e0e0; +} + +.feature-unlock ul { + list-style: none; + padding: 20px 0; +} + +.feature-unlock ul li { + font-size: 1.3em; + color: #00ff88; + margin: 10px 0; + padding: 10px; + background: rgba(0, 255, 136, 0.1); + border-radius: 8px; +} + +.feature-unlock .warning { + color: #ff006e; + font-weight: bold; + font-size: 1.1em; + margin-top: 20px; +} + +.accept-btn { + padding: 20px 60px; + font-size: 1.5em; + font-weight: bold; + background: linear-gradient(135deg, #00ff88, #00aa55); + border: 3px solid #fff; + border-radius: 15px; + color: #000; + cursor: pointer; + transition: all 0.3s ease; +} + +.accept-btn:hover { + transform: scale(1.05); + box-shadow: 0 0 30px rgba(0, 255, 136, 0.6); +} + +/* Denial Training */ +.denial-training-container { + padding: 60px; + text-align: center; + border-radius: 20px; + min-height: 400px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + transition: all 0.5s ease; +} + +.denial-training-container.stroking-period { + background: linear-gradient(135deg, #1a3a1a, #0a2a0a); + border: 4px solid #00ff88; +} + +.denial-training-container.denial-period { + background: linear-gradient(135deg, #3a1a1a, #2a0a0a); + border: 4px solid #ff006e; +} + +.denial-training-container h3 { + font-size: 3em; + margin-bottom: 30px; +} + +.denial-instruction { + font-size: 1.8em; + margin: 20px 0; + font-weight: bold; +} + +.denial-timer { + font-size: 5em; + font-weight: bold; + margin: 30px 0; + font-family: 'Courier New', monospace; +} + +.denial-progress { + font-size: 1.3em; + color: #aaa; + margin-top: 20px; +} + +.denial-complete { + padding: 60px; + text-align: center; + background: linear-gradient(135deg, #1a2a3a, #0a1a2a); + border: 4px solid #8338ec; + border-radius: 20px; +} + +.denial-complete h3 { + font-size: 2.5em; + color: #8338ec; + margin-bottom: 20px; +} + +/* Stop Stroking */ +.stop-stroking-container { + padding: 60px; + text-align: center; + border-radius: 20px; + min-height: 400px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.stop-stroking-container h2 { + font-size: 3.5em; + color: #ff006e; + text-shadow: 0 0 30px #ff006e; + margin-bottom: 30px; + animation: warning-pulse 1s infinite; +} + +.stop-instruction { + font-size: 2em; + font-weight: bold; + margin: 20px 0; +} + +.stop-timer { + font-size: 6em; + font-weight: bold; + margin: 40px 0; + font-family: 'Courier New', monospace; + color: #ff006e; + text-shadow: 0 0 40px #ff006e; +} + +.stop-warning { + font-size: 1.3em; + color: #aaa; + margin-top: 20px; +} + +.stop-complete { + padding: 60px; + text-align: center; + background: linear-gradient(135deg, #1a3a1a, #0a2a0a); + border: 4px solid #00ff88; + border-radius: 20px; +} + +.stop-complete h3 { + font-size: 2.5em; + color: #00ff88; + margin-bottom: 20px; +} + +/* Popup Image */ +.popup-image-container { + padding: 40px; + text-align: center; +} + +.popup-content { + background: #1a1a1a; + border: 3px solid #ff006e; + border-radius: 20px; + padding: 30px; + max-width: 800px; + margin: 0 auto 30px; + box-shadow: 0 0 50px rgba(255, 0, 110, 0.5); +} + +.popup-img { + max-width: 100%; + max-height: 500px; + border-radius: 12px; + margin-bottom: 20px; +} + +.popup-message { + font-size: 1.8em; + font-weight: bold; + color: #fff; + margin: 20px 0; +} + +.popup-timer { + font-size: 1.2em; + color: #aaa; + margin-top: 15px; +} + +.acknowledge-btn { + padding: 15px 50px; + font-size: 1.4em; + font-weight: bold; + background: linear-gradient(135deg, #ff006e, #8338ec); + border: 3px solid #fff; + border-radius: 15px; + color: #fff; + cursor: pointer; + transition: all 0.3s ease; +} + +.acknowledge-btn:hover { + transform: scale(1.05); + box-shadow: 0 0 30px rgba(255, 0, 110, 0.6); +} + +/* Timer Display (reusable) */ +.timer-display { + position: absolute; + top: 20px; + left: 20px; + background: rgba(0, 0, 0, 0.9); + padding: 15px 25px; + border-radius: 10px; + border: 2px solid #8338ec; + font-size: 1.5em; + font-weight: bold; + color: #fff; + z-index: 20; +} + +/* Success Messages */ +.success-message { + background: linear-gradient(135deg, #1a3a1a, #0a2a0a); + border: 3px solid #00ff88; + border-radius: 15px; + padding: 30px; + margin: 20px 0; + font-size: 1.5em; + font-weight: bold; + color: #00ff88; + text-align: center; + box-shadow: 0 0 30px rgba(0, 255, 136, 0.3); +} + diff --git a/src/styles/styles.css b/src/styles/styles.css index ee91cca..5efbbd7 100644 --- a/src/styles/styles.css +++ b/src/styles/styles.css @@ -5194,6 +5194,224 @@ input[type="number"]:focus, input[type="text"]:focus, select:focus { 100% { transform: scale(1); } } +/* =========================================== + INVENTORY QUESTIONNAIRE STYLING + =========================================== */ + +.inventory-questionnaire { + max-width: 800px; + margin: 20px auto; +} + +.inventory-category { + background: rgba(255, 255, 255, 0.05); + border-radius: 12px; + padding: 20px; + margin-bottom: 20px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.category-title { + color: rgba(255, 255, 255, 0.95); + font-size: 20px; + font-weight: bold; + margin-bottom: 15px; + padding-bottom: 10px; + border-bottom: 2px solid rgba(255, 255, 255, 0.2); +} + +.inventory-items { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 15px; + padding: 10px 0; +} + +.inventory-item { + padding: 10px; + background: rgba(255, 255, 255, 0.03); + border-radius: 8px; + transition: background 0.2s; +} + +.inventory-item:hover { + background: rgba(255, 255, 255, 0.08); +} + +.checkbox-label { + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; + color: rgba(255, 255, 255, 0.9); + font-size: 16px; +} + +.inventory-checkbox { + width: 20px; + height: 20px; + cursor: pointer; +} + +.select-label { + display: flex; + flex-direction: column; + gap: 8px; + color: rgba(255, 255, 255, 0.9); + font-size: 16px; +} + +.inventory-select { + padding: 8px 12px; + border-radius: 6px; + background: rgba(0, 0, 0, 0.3); + color: rgba(255, 255, 255, 0.95); + border: 1px solid rgba(255, 255, 255, 0.2); + font-size: 14px; + cursor: pointer; + transition: all 0.2s; +} + +.inventory-select:hover { + background: rgba(0, 0, 0, 0.4); + border-color: rgba(255, 255, 255, 0.4); +} + +.inventory-select:focus { + outline: none; + border-color: #667eea; + box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2); +} + +/* Inventory Summary Styles */ +.inventory-summary { + background: rgba(255, 255, 255, 0.05); + border-radius: 15px; + padding: 30px; + margin: 20px 0; + border: 2px solid rgba(255, 255, 255, 0.1); +} + +.inventory-summary h3 { + color: rgba(255, 255, 255, 0.95); + font-size: 24px; + text-align: center; + margin-bottom: 20px; +} + +.tier-badge { + display: inline-block; + padding: 10px 30px; + border-radius: 25px; + font-size: 20px; + font-weight: bold; + margin: 10px 0 20px; +} + +.tier-badge.tier-1 { + background: linear-gradient(135deg, #ffc0cb 0%, #ffffff 100%); + color: #ff1493; + border: 2px solid #ff69b4; +} + +.tier-badge.tier-2 { + background: linear-gradient(135deg, #ba68c8 0%, #f48fb1 100%); + color: #ffffff; + border: 2px solid #9c27b0; +} + +.tier-badge.tier-3 { + background: linear-gradient(135deg, #ff1493 0%, #ffc0cb 50%, #ff69b4 100%); + color: #ffffff; + border: 2px solid #ffd700; +} + +.tier-badge.tier-4 { + background: linear-gradient(135deg, #b71c1c 0%, #000000 100%); + color: #ff5252; + border: 2px solid #ff5252; +} + +.tier-badge.tier-5 { + background: linear-gradient(135deg, #000000 0%, #ff1493 50%, #000000 100%); + color: #ff1493; + border: 2px solid #00ff00; + box-shadow: 0 0 20px rgba(255, 20, 147, 0.5); +} + +.summary-stats { + display: flex; + justify-content: space-around; + margin: 20px 0; + flex-wrap: wrap; + gap: 15px; +} + +.summary-stats .stat { + background: rgba(255, 255, 255, 0.1); + padding: 15px 25px; + border-radius: 10px; + text-align: center; + min-width: 150px; +} + +.stat-label { + display: block; + color: rgba(255, 255, 255, 0.7); + font-size: 14px; + margin-bottom: 5px; +} + +.stat-value { + display: block; + color: rgba(255, 255, 255, 0.95); + font-size: 28px; + font-weight: bold; +} + +.inventory-lists { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 20px; + margin-top: 20px; +} + +.item-category { + background: rgba(255, 255, 255, 0.05); + border-radius: 10px; + padding: 15px; +} + +.item-category h4 { + color: rgba(255, 255, 255, 0.9); + font-size: 16px; + margin-bottom: 10px; + padding-bottom: 8px; + border-bottom: 1px solid rgba(255, 255, 255, 0.2); +} + +.item-category ul { + list-style: none; + padding: 0; + margin: 0; +} + +.item-category li { + color: rgba(255, 255, 255, 0.8); + font-size: 14px; + padding: 5px 0; + padding-left: 15px; + position: relative; +} + +.item-category li:before { + content: "✓"; + position: absolute; + left: 0; + color: #28a745; + font-weight: bold; +} + /* =========================================== INTERLUDE INTERFACE STYLING (Webcam Mirror, Focus Session, etc.) =========================================== */ diff --git a/src/utils/backupManager.js b/src/utils/backupManager.js index 1b52685..5cea99f 100644 --- a/src/utils/backupManager.js +++ b/src/utils/backupManager.js @@ -15,8 +15,12 @@ class BackupManager { init() { console.log('🛡️ Backup Manager initialized'); - this.startAutoBackup(); + // Perform aggressive cleanup first + this.performEmergencyCleanup(); this.cleanupOldBackups(); + // Disable auto-backup to prevent quota issues + // this.startAutoBackup(); + console.log('⚠️ Auto-backup disabled to prevent storage quota issues'); } /** @@ -162,44 +166,33 @@ class BackupManager { try { console.log('🚨 Starting emergency storage cleanup...'); - // Clean up old backups first - keep only 1 - this.cleanupOldBackups(1); + // Delete ALL backups immediately + const keys = Object.keys(localStorage); + const backupKeys = keys.filter(key => key.startsWith(this.backupPrefix)); + backupKeys.forEach(key => localStorage.removeItem(key)); + console.log(`🧹 Emergency: Removed ${backupKeys.length} backups`); - // Clean up verification photos aggressively - const verificationPhotos = JSON.parse(localStorage.getItem('verificationPhotos') || '[]'); - if (verificationPhotos.length > 2) { - const recent = verificationPhotos.slice(-2); - localStorage.setItem('verificationPhotos', JSON.stringify(recent)); - console.log(`🧹 Emergency: Reduced verification photos to ${recent.length}`); - } - - // Clean up captured photos aggressively - const capturedPhotos = JSON.parse(localStorage.getItem('capturedPhotos') || '[]'); - if (capturedPhotos.length > 3) { - const recent = capturedPhotos.slice(-3); - localStorage.setItem('capturedPhotos', JSON.stringify(recent)); - console.log(`🧹 Emergency: Reduced captured photos to ${recent.length}`); - } + // Clean up ALL photos - don't keep any in localStorage + localStorage.removeItem('verificationPhotos'); + localStorage.removeItem('capturedPhotos'); + localStorage.removeItem('photoGallery'); + console.log(`🧹 Emergency: Removed all photo data from localStorage`); // Clean up any old individual photo keys - const keys = Object.keys(localStorage); const photoKeys = keys.filter(key => key.startsWith('verificationPhoto_') || key.startsWith('capturedPhoto_') || key.startsWith('photo_') ); - if (photoKeys.length > 5) { - const toRemove = photoKeys.slice(0, -5); // Keep only 5 most recent - toRemove.forEach(key => { - const value = localStorage.getItem(key); - if (value && value.startsWith('blob:')) { - URL.revokeObjectURL(value); - } - localStorage.removeItem(key); - }); - console.log(`🧹 Emergency: Removed ${toRemove.length} old photo keys`); - } + photoKeys.forEach(key => { + const value = localStorage.getItem(key); + if (value && value.startsWith('blob:')) { + URL.revokeObjectURL(value); + } + localStorage.removeItem(key); + }); + console.log(`🧹 Emergency: Removed ${photoKeys.length} old photo keys`); // Calculate storage usage after cleanup const usage = this.calculateStorageUsage(); diff --git a/src/utils/desktop-file-manager.js b/src/utils/desktop-file-manager.js index 0e7d5ab..7193a8d 100644 --- a/src/utils/desktop-file-manager.js +++ b/src/utils/desktop-file-manager.js @@ -514,6 +514,11 @@ class DesktopFileManager { if (!this.isElectron) { return; } + + if (!this.dataManager) { + console.warn('⚠️ DataManager not available, skipping linked directories load'); + return; + } try { const data = this.dataManager.get('linkedVideoDirectories'); diff --git a/src/utils/inventoryManager.js b/src/utils/inventoryManager.js new file mode 100644 index 0000000..283dfb2 --- /dev/null +++ b/src/utils/inventoryManager.js @@ -0,0 +1,626 @@ +/** + * InventoryManager - Handles player inventory tracking and progression path generation + * Determines tier based on available items and creates personalized photo challenges + */ + +class InventoryManager { + constructor() { + this.inventory = null; + this.tier = 0; + this.totalItems = 0; + } + + /** + * Store player's inventory from questionnaire + */ + setInventory(inventoryData) { + this.inventory = inventoryData; + this.totalItems = this.countTotalItems(); + this.tier = this.calculateTier(); + + console.log('📦 Inventory set:', this.totalItems, 'items, Tier', this.tier); + return { + inventory: this.inventory, + tier: this.tier, + totalItems: this.totalItems + }; + } + + /** + * Count total non-none items across all categories + */ + countTotalItems() { + let count = 0; + + // Count clothing items + for (const [key, value] of Object.entries(this.inventory.clothing || {})) { + if (value && value !== 'none') count++; + } + + // Count accessories + for (const [key, value] of Object.entries(this.inventory.accessories || {})) { + if (value && value !== 'none') count++; + } + + // Count toys + for (const [key, value] of Object.entries(this.inventory.toys || {})) { + if (value && value !== 'none') count++; + } + + // Count environment items (booleans) + for (const [key, value] of Object.entries(this.inventory.environment || {})) { + if (value === true) count++; + } + + return count; + } + + /** + * Calculate tier based on total items + */ + calculateTier() { + if (this.totalItems >= 18) return 5; + if (this.totalItems >= 13) return 4; + if (this.totalItems >= 8) return 3; + if (this.totalItems >= 4) return 2; + return 1; + } + + /** + * Get available items as array + */ + getAvailableItems() { + const items = []; + + // Collect clothing items + for (const [key, value] of Object.entries(this.inventory.clothing || {})) { + if (value && value !== 'none') { + items.push({ category: 'clothing', type: key, level: value }); + } + } + + // Collect accessories + for (const [key, value] of Object.entries(this.inventory.accessories || {})) { + if (value && value !== 'none') { + items.push({ category: 'accessories', type: key, level: value }); + } + } + + // Collect toys + for (const [key, value] of Object.entries(this.inventory.toys || {})) { + if (value && value !== 'none') { + items.push({ category: 'toys', type: key, level: value }); + } + } + + return items; + } + + /** + * Check if player has specific item + */ + hasItem(itemType) { + const allItems = { + ...this.inventory.clothing, + ...this.inventory.accessories, + ...this.inventory.toys, + ...this.inventory.environment + }; + + return allItems[itemType] && allItems[itemType] !== 'none'; + } + + /** + * Get item level (none/basic/sexy/multiple, etc.) + */ + getItemLevel(itemType) { + const allItems = { + ...this.inventory.clothing, + ...this.inventory.accessories, + ...this.inventory.toys + }; + + return allItems[itemType] || 'none'; + } + + /** + * Generate photo progression based on tier + */ + generatePhotoProgression() { + const availableItems = this.getAvailableItems(); + const photoCount = this.getPhotoCountForTier(); + + console.log(`📸 Generating ${photoCount} photo challenges for Tier ${this.tier}`); + + const progression = []; + + for (let i = 1; i <= photoCount; i++) { + const challenge = this.generatePhotoChallenge(i, photoCount, availableItems); + progression.push(challenge); + } + + return progression; + } + + /** + * Get photo count based on tier + */ + getPhotoCountForTier() { + const counts = { + 1: 5, + 2: 10, + 3: 15, + 4: 20, + 5: 25 + }; + return counts[this.tier] || 5; + } + + /** + * Generate individual photo challenge + */ + generatePhotoChallenge(challengeNumber, totalChallenges, availableItems) { + const intensity = this.calculateChallengeIntensity(challengeNumber, totalChallenges); + const requiredItems = this.selectItemsForChallenge(challengeNumber, availableItems); + const includesEdging = this.shouldIncludeEdging(challengeNumber, totalChallenges, requiredItems); + const poseCategory = this.determinePoseCategory(requiredItems, includesEdging); + + // Generate instruction text + const instruction = this.generateInstructionText(challengeNumber, totalChallenges, requiredItems, poseCategory, includesEdging); + + return { + number: challengeNumber, + intensity: intensity, + requiredItems: requiredItems, + edging: includesEdging, + poseCategory: poseCategory, + instruction: instruction + }; + } + + /** + * Generate instruction text for photo challenge + */ + generateInstructionText(challengeNumber, totalChallenges, requiredItems, poseCategory, includesEdging) { + // Build item list with specific instructions for special items + const itemDescriptions = []; + const specialInstructions = []; + + requiredItems.forEach(item => { + if (item === 'dildos-oral') { + itemDescriptions.push('dildo'); + specialInstructions.push('suck the dildo or slap your face with it'); + } else { + itemDescriptions.push(item); + } + }); + + const progressText = `Photo ${challengeNumber} of ${totalChallenges}`; + const edgingText = includesEdging ? ' Edge while posing.' : ''; + + // Handle nude photos + if (requiredItems.length === 0) { + const nudePoses = [ + 'Pose nude for the camera', + 'Strike a confident nude pose', + 'Show yourself completely exposed', + 'Display your naked body', + 'Present yourself with nothing on', + 'Kneel nude and look at the camera', + 'Bend over and show everything', + 'Lie on your back nude', + 'Stand with legs spread', + 'Sit nude and spread your legs' + ]; + const nudeText = nudePoses[challengeNumber % nudePoses.length]; + return `${progressText} - ${nudeText}.${edgingText}`; + } + + const itemList = itemDescriptions.join(', '); + + // Check if user has multiple of any items and suggest variety + const varietyItems = this.getVarietyItems(requiredItems); + const varietyText = varietyItems.length > 0 + ? ` Try a different ${varietyItems.join(' or ')} than last time.` + : ''; + + // Special instructions for specific items + const specialText = specialInstructions.length > 0 + ? ` ${specialInstructions.join('. ')}.` + : ''; + + // Detailed pose instructions based on category + const poseInstructions = { + 'standing': [ + 'Stand with hands on hips', + 'Stand with arms behind your head', + 'Strike a confident standing pose', + 'Stand and show off your outfit', + 'Stand with one leg forward' + ], + 'sitting': [ + 'Sit with legs crossed', + 'Sit and spread your legs', + 'Sit on the edge of a chair', + 'Sit with hands on your knees', + 'Recline while seated' + ], + 'kneeling': [ + 'Kneel with hands behind your back', + 'Kneel and look up at the camera', + 'Kneel with legs spread', + 'Kneel and present yourself', + 'Kneel on all fours' + ], + 'lying': [ + 'Lie on your back', + 'Lie on your side', + 'Lie face down', + 'Recline and show off', + 'Lie with legs spread' + ], + 'mirror': [ + 'Admire yourself in the mirror', + 'Take a mirror selfie', + 'Pose in front of the mirror', + 'Check yourself out in the mirror', + 'Show your outfit in the mirror' + ], + 'provocative': [ + 'Bend over and look back', + 'Arch your back', + 'Strike a seductive pose', + 'Pose provocatively', + 'Show off your assets' + ], + 'submissive': [ + 'Kneel submissively', + 'Lower your head in submission', + 'Present yourself submissively', + 'Assume a submissive position', + 'Display your obedience' + ], + 'edging': [ + 'Edge while looking at the camera', + 'Edge and pose', + 'Touch yourself while posing', + 'Edge in position', + 'Stroke while holding the pose' + ], + 'toy': [ + 'Display your toys', + 'Pose with toys visible', + 'Show off your toy collection', + 'Present your toys', + 'Hold your toys for the camera' + ], + 'heel': [ + 'Show off your heels - legs extended', + 'Stand on tiptoes in your heels', + 'Sit and display your heels', + 'Pose to highlight your heels', + 'Walk pose in your heels' + ], + 'dress': [ + 'Twirl in your dress/skirt', + 'Lift your dress/skirt slightly', + 'Model your outfit', + 'Show off your dress/skirt', + 'Pose to display your outfit' + ], + 'bra': [ + 'Show off your bra', + 'Display your lingerie', + 'Cup your chest', + 'Present your bra', + 'Pose to highlight your lingerie' + ], + 'panty': [ + 'Show off your panties', + 'Display what you\'re wearing', + 'Pull your panties to the side', + 'Present yourself in panties', + 'Bend over in your panties' + ] + }; + + // Get pose text - use challenge number to rotate through options + const poseOptions = poseInstructions[poseCategory] || [ + 'Strike a confident pose', + 'Pose seductively', + 'Show everything to the camera', + 'Present yourself', + 'Display yourself' + ]; + const poseText = poseOptions[challengeNumber % poseOptions.length]; + + return `${progressText} - ${poseText} wearing ${itemList}.${specialText}${varietyText}${edgingText}`; + } + + /** + * Get items that user has multiple of for variety suggestions + */ + getVarietyItems(requiredItems) { + const varietyItems = []; + + requiredItems.forEach(itemKey => { + const level = this.getItemLevel(itemKey); + if (level === 'multiple') { + // Convert item key to friendly name + const friendlyNames = { + 'panties': 'pair of panties', + 'bras': 'bra', + 'lingerie': 'lingerie set', + 'dresses': 'dress', + 'skirts': 'skirt', + 'pantyhose': 'pantyhose', + 'heels': 'heels', + 'wigs': 'wig' + }; + if (friendlyNames[itemKey]) { + varietyItems.push(friendlyNames[itemKey]); + } + } + }); + + return varietyItems; + } + + /** + * Calculate intensity (0-1) based on progression + */ + calculateChallengeIntensity(challengeNumber, totalChallenges) { + return challengeNumber / totalChallenges; + } + + /** + * Select items to use for this specific challenge + * Considers item compatibility and mutual exclusivity + */ + selectItemsForChallenge(challengeNumber, availableItems) { + const items = []; + const intensity = challengeNumber / this.getPhotoCountForTier(); + + // Track what's already selected to avoid conflicts + let hasUnderwear = false; + let hasAnalToy = false; + let hasChastity = false; + + // Early photos (0-15%) - start nude or minimal + if (intensity < 0.15) { + // Nude poses to start + return []; + } + + // Lingerie is a complete set - if selected, use it instead of bra/panties + if (intensity >= 0.25 && this.hasItem('lingerie')) { + items.push('lingerie'); + hasUnderwear = true; + } else { + // Otherwise build from bra and panties separately + if (intensity >= 0.15 && this.hasItem('panties')) { + items.push('panties'); + hasUnderwear = true; + } + + if (intensity >= 0.2 && this.hasItem('bras')) { + items.push('bras'); + } + } + + // Add dress/skirt around 30% (goes over underwear) + if (intensity >= 0.3) { + if (this.hasItem('dresses')) items.push('dresses'); + else if (this.hasItem('skirts')) items.push('skirts'); + } + + // Add pantyhose around 40% (under dress/skirt, over panties) + if (intensity >= 0.4 && this.hasItem('pantyhose')) { + items.push('pantyhose'); + } + + // Add heels around 45% + if (intensity >= 0.45 && this.hasItem('heels')) { + items.push('heels'); + } + + // Add wig around 55% + if (intensity >= 0.55 && this.hasItem('wigs')) { + items.push('wigs'); + } + + // Add makeup around 60% + if (intensity >= 0.6 && this.hasItem('makeup')) { + items.push('makeup'); + } + + // Add jewelry around 65% + if (intensity >= 0.65 && this.hasItem('jewelry')) { + items.push('jewelry'); + } + + // Chastity check - if wearing chastity, mark it + if (intensity >= 0.5 && this.hasItem('chastity')) { + items.push('chastity'); + hasChastity = true; + } + + // Anal toys - only ONE at a time (plug OR dildo, not both) + // Prefer plug first, then switch to dildo later + if (intensity >= 0.5 && intensity < 0.7 && !hasAnalToy) { + if (this.hasItem('plugs')) { + items.push('plugs'); + hasAnalToy = true; + } + } + + // Hand-held toys (can use if no current anal plug, or for specific actions) + // Around 70%, switch from plug to dildo with specific actions + if (intensity >= 0.7 && this.hasItem('dildos')) { + // If we had a plug earlier, remove it and add dildo instead + const plugIndex = items.indexOf('plugs'); + if (plugIndex > -1) { + items.splice(plugIndex, 1); + } + // Dildo with specific action + items.push('dildos-oral'); + hasAnalToy = true; + } + + // Vibrator (can be used regardless of other toys) + if (intensity >= 0.75 && this.hasItem('vibrators') && !hasChastity) { + items.push('vibrators'); + } + + // Restraints around 78% + if (intensity >= 0.78 && this.hasItem('restraints')) { + items.push('restraints'); + } + + // Nipple clamps around 82% + if (intensity >= 0.82 && this.hasItem('nippleClamps')) { + items.push('nippleClamps'); + } + + // Gags around 88% + if (intensity >= 0.88 && this.hasItem('gags')) { + items.push('gags'); + } + + return items; + } + + /** + * Determine if challenge should include edging + * Cannot edge if wearing chastity cage + */ + shouldIncludeEdging(challengeNumber, totalChallenges, requiredItems) { + // No edging if chastity cage is involved + if (requiredItems.includes('chastity')) return false; + + const intensity = challengeNumber / totalChallenges; + + // No edging in first 20% + if (intensity < 0.2) return false; + + // Occasional edging in middle + if (intensity < 0.6) return challengeNumber % 3 === 0; + + // Frequent edging in later stages + if (intensity < 0.8) return challengeNumber % 2 === 0; + + // Almost always edging in final stages + return true; + } + + /** + * Determine pose category based on items + */ + determinePoseCategory(requiredItems, includesEdging) { + // If edging, select edging pose category + if (includesEdging) return 'edging'; + + // If toys present, toy poses + if (requiredItems.some(item => ['plugs', 'dildos', 'chastity', 'gags', 'nippleClamps'].includes(item))) { + return 'toy'; + } + + // If heels, heel poses + if (requiredItems.includes('heels')) return 'heel'; + + // If dress/skirt, dress poses + if (requiredItems.includes('dresses') || requiredItems.includes('skirts')) { + return 'dress'; + } + + // If bra, bra poses + if (requiredItems.includes('bras')) return 'bra'; + + // If just panties, panty poses + if (requiredItems.includes('panties')) return 'panty'; + + // Default to basic + return 'basic'; + } + + /** + * Get inventory summary for display + */ + getInventorySummary() { + const summary = { + tier: this.tier, + totalItems: this.totalItems, + photoCount: this.getPhotoCountForTier(), + itemsByCategory: { + clothing: [], + accessories: [], + toys: [], + environment: [] + } + }; + + // Collect clothing + for (const [key, value] of Object.entries(this.inventory.clothing || {})) { + if (value && value !== 'none') { + summary.itemsByCategory.clothing.push(`${this.formatItemName(key)}: ${value}`); + } + } + + // Collect accessories + for (const [key, value] of Object.entries(this.inventory.accessories || {})) { + if (value && value !== 'none') { + summary.itemsByCategory.accessories.push(`${this.formatItemName(key)}: ${value}`); + } + } + + // Collect toys + for (const [key, value] of Object.entries(this.inventory.toys || {})) { + if (value && value !== 'none') { + summary.itemsByCategory.toys.push(`${this.formatItemName(key)}: ${value}`); + } + } + + // Collect environment + for (const [key, value] of Object.entries(this.inventory.environment || {})) { + if (value === true) { + summary.itemsByCategory.environment.push(this.formatItemName(key)); + } + } + + return summary; + } + + /** + * Format item name for display + */ + formatItemName(key) { + const names = { + panties: 'Panties', + bras: 'Bras', + dresses: 'Dresses', + skirts: 'Skirts', + pantyhose: 'Pantyhose/Stockings', + heels: 'Heels', + wigs: 'Wigs', + lingerie: 'Lingerie', + makeup: 'Makeup', + jewelry: 'Jewelry', + nailPolish: 'Nail Polish', + dildos: 'Dildos', + plugs: 'Butt Plugs', + chastity: 'Chastity Device', + restraints: 'Restraints', + gags: 'Gags', + nippleClamps: 'Nipple Clamps', + mirror: 'Mirror', + fullMirror: 'Full-Length Mirror', + privateSpace: 'Private Space', + phoneStand: 'Phone/Camera Stand' + }; + + return names[key] || key; + } +} + +// Make available globally +window.InventoryManager = InventoryManager; diff --git a/test-academy-ui.html b/test-academy-ui.html new file mode 100644 index 0000000..2ea2852 --- /dev/null +++ b/test-academy-ui.html @@ -0,0 +1,200 @@ + + + + + + Academy UI Integration Test + + + + +
+

🎓 Academy UI Integration Test

+ +
+

Manual Tests

+
+ + + + + + +
+
+
+ + +
+
+ + + + + + + + + + + diff --git a/test-campaign-manager.html b/test-campaign-manager.html new file mode 100644 index 0000000..5564816 --- /dev/null +++ b/test-campaign-manager.html @@ -0,0 +1,293 @@ + + + + + + Campaign Manager Test - Subphase 1.1 + + + +

🎓 Campaign Manager Test - Subphase 1.1

+ +
+

Campaign Progression System

+

Testing basic level unlocking, completion tracking, and failure states.

+ + + + + +
+
+ +
+

Manual Testing

+ + + + + +
+
+ +
+

Current Progress

+
+
+ + + + + + + + + + diff --git a/test-library-manager.html b/test-library-manager.html new file mode 100644 index 0000000..189b9b1 --- /dev/null +++ b/test-library-manager.html @@ -0,0 +1,609 @@ + + + + + + Library Manager Test Suite + + + +
+

📚 Library Manager Test Suite

+ + +
+

Automated Tests

+ +
+
+ + +
+

Manual Testing

+
+ + + + + + + + + +
+
+
+ + +
+

Current Library State

+
+
+
+ + + + + + + + diff --git a/test-preference-manager.html b/test-preference-manager.html new file mode 100644 index 0000000..7a17593 --- /dev/null +++ b/test-preference-manager.html @@ -0,0 +1,526 @@ + + + + + + Preference Manager Test Suite + + + +
+

🎯 Preference Manager Test Suite

+ + +
+

Automated Tests

+ +
+
+ + +
+

Manual Testing

+
+ + + + + + + + +
+
+
+ + +
+

Interactive Preference Editor

+
+
+ + +
+

Current State

+
+
+
+ + + + + + + + diff --git a/training-academy.html b/training-academy.html index 779f176..0af3a8e 100644 --- a/training-academy.html +++ b/training-academy.html @@ -10,6 +10,7 @@ +