docs: Update levels.md to reflect actual XP system and add user feedback analysis

- Fixed level XP requirements to match exponential scaling system
- Updated achievements to reflect actual implementation
- Removed unlock features that aren't implemented yet
- Added comprehensive user feedback analysis with actionable items
- Corrected Level 14 name from Hedonistic to Submissive
- Updated progression tips for realistic XP earning strategies
This commit is contained in:
dilgenfritz 2025-11-24 09:04:25 -06:00
parent c40ed278e0
commit fabba36fe6
6 changed files with 1067 additions and 141 deletions

View File

@ -0,0 +1,154 @@
# 🎯 User Feedback Analysis - November 2025
## 📝 Feedback Summary
**Overall Impression**: Positive user experience with regular usage during gooning sessions. User appreciates responsiveness and speed, but identifies key areas for improvement in customization, persistence, and bug fixes.
**User Profile**: Self-described "Porn Designer" with experience in captions and video creation, offering asset collaboration.
---
## 🎨 UI/UX Feedback
### ✅ **Positive**
- Background video deactivation feature appreciated
- Button responsiveness and speed are excellent
- Overall interface functions well
### 🔧 **Areas for Improvement**
- **Background Video**: Either disable by default or add opacity mask
- **Quick Play Mode**: Needs more detailed descriptions and guidance
- **User Guidance**: More explanatory text throughout interface
---
## 🎨 Design & Customization Requests
### 🎯 **High Priority**
- **Theme Customization**: Beyond purple color scheme
- **Profile System**: Personal profile with custom image upload
- **Preset Management**: Save/load session configurations
- **Persistence**: Retain customizations between sessions
### 💡 **User Suggestion**
- User offers collaboration on asset creation (captions, videos)
---
## 🐛 Bug Reports
### 🚨 **Critical Issues**
1. **Cinema Breakage**: Cinema mode crashes requiring restart
2. **Task-Porn Attribution**: Some tasks missing associated content (tagging issue)
3. **Gamification Tracking**: No interaction detection - 20 minute idle session still counted
### 🔍 **Technical Details**
- Interaction detection system needs implementation
- Content tagging system requires review
- Cinema stability issues need investigation
---
## 🎮 Gamification & Features
### ✅ **Working Well**
- User sees improvements in gaming tracking
- Regular usage indicates good engagement
### 🎯 **Enhancement Requests**
- **More Achievements**: Expand achievement system
- **Story Mode**: Narrative-driven gooning experience
- **Better Progress Tracking**: More sophisticated interaction detection
---
## 📋 Action Item Priorities
### 🔥 **Critical (Fix Immediately)**
#### 🐛 Bug Fixes
- [ ] **Fix Cinema Crashes** - Investigate and resolve cinema mode stability
- [ ] **Implement Interaction Detection** - Prevent idle time from counting toward statistics
- [ ] **Fix Task-Porn Attribution** - Review and fix content tagging system
#### 🎨 UX Improvements
- [ ] **Default Background Video Off** - Make background video disabled by default OR add opacity mask
- [ ] **Add Quick Play Descriptions** - Provide detailed explanations for quick play features
### 🎯 **High Priority (Next Sprint)**
#### 💾 Persistence System
- [ ] **Implement Preset Saving** - Allow users to save session configurations
- [ ] **Add Preset Loading** - Quick restoration of saved settings
- [ ] **Session Memory** - Retain customizations between app restarts
#### 🎨 Customization System
- [ ] **Theme Engine** - Expandable color scheme system beyond purple
- [ ] **Profile System** - User profile with custom image upload
- [ ] **Custom Asset Management** - Framework for user-contributed content
### 🚀 **Medium Priority (Future Development)**
#### 🎮 Enhanced Gamification
- [ ] **Expanded Achievement System** - More varied and engaging achievements
- [ ] **Interaction Tracking** - Sophisticated user engagement detection
- [ ] **Progress Analytics** - Better tracking and feedback systems
#### 📖 New Features
- [ ] **Story Mode Development** - Narrative-driven experience system
- [ ] **Asset Collaboration Framework** - System for community contributions
- [ ] **Advanced Customization Options** - Deeper personalization features
### 📝 **Documentation & Planning**
- [ ] **User Onboarding Guide** - Comprehensive quick play explanations
- [ ] **Asset Contribution Guidelines** - Framework for user-generated content
- [ ] **Story Mode Design Document** - Detailed narrative system planning
---
## 🤝 Collaboration Opportunities
**User Offers**:
- Caption creation assistance
- Video asset development
- Story mode content collaboration
**Action**: Reach out to establish collaboration framework and contribution guidelines.
---
## 📊 Success Metrics
**Current State**:
- ✅ Regular user engagement
- ✅ Positive response to core functionality
- ✅ User willing to contribute content
**Target Improvements**:
- 🎯 Zero critical crashes
- 🎯 Persistent user preferences
- 🎯 Enhanced customization options
- 🎯 Robust interaction detection
---
## 🗓️ Implementation Timeline
### **Week 1-2**: Critical Bug Fixes
- Cinema stability
- Interaction detection
- Task attribution
### **Week 3-4**: Core UX Improvements
- Background video defaults
- Quick play descriptions
- Basic preset system
### **Month 2**: Advanced Features
- Full theme engine
- Profile system
- Story mode foundation
---
*This feedback indicates a engaged user with valuable insights and collaboration potential. Priority should be on fixing critical bugs while building the persistence and customization systems that will significantly improve user experience.*

View File

@ -1,17 +1,18 @@
# 🎯 Level System - webGame # 🎯 Level System - webGame
## Overview ## Overview
The webGame uses an XP-based progression system where players advance through levels by earning Experience Points (XP) across all game modes. Each level requires 100 XP to advance, providing a steady and rewarding progression curve. The webGame uses an exponential XP-based progression system where players advance through levels by earning Experience Points (XP) across all game modes. Each level requires increasing amounts of XP, creating a challenging but rewarding progression curve.
**Base Formula:** Level = (Total XP ÷ 100) + 1 **Level Formula:** Dynamic XP requirements with exponential scaling for higher levels
--- ---
## XP Sources ## XP Sources
### 📺 Porn Cinema ### 📺 Porn Cinema
- **Watch Time XP**: 1 XP per 5 minutes of viewing - **Watch Time XP**: 1 XP per 5 minutes of continuous viewing
- **Video Completion**: Videos must reach 90% completion to count toward stats - **Video Completion**: Videos must reach 90% completion to count toward statistics
- **Continuous Tracking**: XP awarded every 30 seconds during active viewing
### ⚡ Quick Play ### ⚡ Quick Play
- **Task Completion XP**: - **Task Completion XP**:
@ -34,219 +35,136 @@ The webGame uses an XP-based progression system where players advance through le
## Level Breakdown (1-20) ## Level Breakdown (1-20)
### 🌱 **Level 1** - *Virgin* ### 🌱 **Level 1** - *Virgin*
- **XP Required**: 0-99 XP - **XP Required**: 0 XP
- **Description**: Welcome to webGame! Your first taste of pleasure awaits. - **Description**: Welcome to webGame! Your first taste of pleasure awaits.
- **Unlocks**:
- Access to all basic game modes
- Profile customization
- Basic statistics tracking
### 🌿 **Level 2** - *Curious* ### 🌿 **Level 2** - *Curious*
- **XP Required**: 100-199 XP - **XP Required**: 10 XP
- **Description**: Your curiosity is growing! Start exploring your desires. - **Description**: Your curiosity is growing! Start exploring your desires.
- **Unlocks**:
- Achievement "First Steps" available
- Enhanced stat tracking
- Basic playlist creation
### 🌱 **Level 3** - *Eager* ### 🌱 **Level 3** - *Eager*
- **XP Required**: 200-299 XP - **XP Required**: 25 XP
- **Description**: An eager participant! You're developing your appetites. - **Description**: An eager participant! You're developing your appetites.
- **Unlocks**:
- Achievement "Early Bird" available
- Extended session tracking
- Profile bio customization
### 🌿 **Level 4** - *Aroused* ### 🌿 **Level 4** - *Aroused*
- **XP Required**: 300-399 XP - **XP Required**: 48 XP
- **Description**: Your arousal is building! Keep feeding your desires. - **Description**: Your arousal is building! Keep feeding your desires.
- **Unlocks**:
- Advanced statistics dashboard
- Streak tracking begins
- Achievement "Marathon Viewer" available
### 🌟 **Level 5** - *Lustful* ### 🌟 **Level 5** - *Lustful*
- **XP Required**: 400-499 XP - **XP Required**: 82 XP
- **Description**: Consumed by lust and craving more experiences! - **Description**: Consumed by lust and craving more experiences!
- **Unlocks**:
- Achievement "Level Up" unlocked
- Enhanced profile features
- Priority support features
### 🔥 **Level 6** - *Passionate* ### 🔥 **Level 6** - *Passionate*
- **XP Required**: 500-599 XP - **XP Required**: 133 XP
- **Description**: Your passion burns hot with unbridled desire. - **Description**: Your passion burns hot with unbridled desire.
- **Unlocks**:
- Achievement "XP Master" unlocked
- Advanced playlist management
- Custom themes (future feature)
### ⭐ **Level 7** - *Addicted* ### ⭐ **Level 7** - *Addicted*
- **XP Required**: 600-699 XP - **XP Required**: 209 XP
- **Description**: Hopelessly addicted to the rush of pleasure! - **Description**: Hopelessly addicted to the rush of pleasure!
- **Unlocks**:
- Achievement "Consistency King" available
- Extended activity history
- Advanced export options
### 🎯 **Level 8** - *Obsessed* ### 🎯 **Level 8** - *Obsessed*
- **XP Required**: 700-799 XP - **XP Required**: 323 XP
- **Description**: Your obsession drives you to new heights of ecstasy. - **Description**: Your obsession drives you to new heights of ecstasy.
- **Unlocks**:
- Achievement "Playlist Curator" available
- Enhanced statistics breakdown
- Advanced profile customization
### 🏆 **Level 9** - *Deviant* ### 🏆 **Level 9** - *Deviant*
- **XP Required**: 800-899 XP - **XP Required**: 494 XP
- **Description**: A true deviant exploring the depths of desire! - **Description**: A true deviant exploring the depths of desire!
- **Unlocks**:
- Multiple achievement categories
- Detailed performance analytics
- Achievement showcase features
### 💎 **Level 10** - *Kinky* ### 💎 **Level 10** - *Kinky*
- **XP Required**: 900-999 XP - **XP Required**: 751 XP
- **Description**: Welcome to the kinky elite! Your fetishes are flourishing. - **Description**: Welcome to the kinky elite! Your fetishes are flourishing.
- **Unlocks**:
- Elite status badge
- Advanced features access
- Achievement "Video Collector" available
### 🌟 **Level 11** - *Perverted* ### 🌟 **Level 11** - *Perverted*
- **XP Required**: 1000-1099 XP - **XP Required**: 1,137 XP
- **Description**: A seasoned pervert with extensive experience in debauchery. - **Description**: A seasoned pervert with extensive experience in debauchery.
- **Unlocks**:
- Veteran status recognition
- Historical data archives
- Legacy achievement tracking
### 🔮 **Level 12** - *Depraved* ### 🔮 **Level 12** - *Depraved*
- **XP Required**: 1100-1199 XP - **XP Required**: 1,716 XP
- **Description**: You've mastered the art of depravity and corruption! - **Description**: You've mastered the art of depravity and corruption!
- **Unlocks**:
- Master tier privileges
- Advanced customization options
- Exclusive features access
### 👑 **Level 13** - *Dominant* ### 👑 **Level 13** - *Dominant*
- **XP Required**: 1200-1299 XP - **XP Required**: 2,585 XP
- **Description**: A dominant force commanding respect and submission! - **Description**: A dominant force commanding respect and submission!
- **Unlocks**:
- Champion status badge
- Premium feature previews
- Community recognition features
### 🚀 **Level 14** - *Hedonistic* ### 🚀 **Level 14** - *Submissive*
- **XP Required**: 1300-1399 XP - **XP Required**: 3,889 XP
- **Description**: Embracing submission and control in the pursuit of pleasure!
### 🌌 **Level 15** - *Hedonist*
- **XP Required**: 5,844 XP
- **Description**: Pure hedonism guides your every pleasure-seeking move! - **Description**: Pure hedonism guides your every pleasure-seeking move!
- **Unlocks**:
- Legendary badge and privileges
- Beta feature access
- Advanced analytics dashboard
### 🌌 **Level 15** - *Decadent*
- **XP Required**: 1400-1499 XP
- **Description**: You've reached decadent levels of indulgence!
- **Unlocks**:
- Cosmic tier recognition
- Exclusive content access
- Advanced progression tracking
### ⚡ **Level 16** - *Insatiable* ### ⚡ **Level 16** - *Insatiable*
- **XP Required**: 1500-1599 XP - **XP Required**: 8,777 XP
- **Description**: Your insatiable appetite knows no bounds! - **Description**: Your insatiable appetite knows no bounds!
- **Unlocks**:
- Transcendent status
- Ultimate customization options
- Developer preview features
### 🔥 **Level 17** - *Sinful* ### 🔥 **Level 17** - *Transcendent*
- **XP Required**: 1600-1699 XP - **XP Required**: 13,176 XP
- **Description**: Deliciously sinful dedication to carnal pleasures! - **Description**: Transcending mortal desire and reaching new heights!
- **Unlocks**:
- Immortal tier privileges
- Lifetime achievement tracking
- Exclusive immortal features
### 🌠 **Level 18** - *Forbidden* ### 🌠 **Level 18** - *Enlightened*
- **XP Required**: 1700-1799 XP - **XP Required**: 19,775 XP
- **Description**: You've achieved forbidden status in the realm of desire! - **Description**: You've achieved enlightened pleasure in the realm of desire!
- **Unlocks**:
- Celestial recognition
- Advanced achievement categories
- Special celestial features
### 🏛️ **Level 19** - *Godlike* ### 🏛️ **Level 19** - *Godlike*
- **XP Required**: 1800-1899 XP - **XP Required**: 29,673 XP
- **Description**: Godlike levels of sexual prowess and commitment! - **Description**: Godlike levels of sexual prowess and commitment!
- **Unlocks**:
- Godlike status badge
- Ultimate privileges
- All premium features unlocked
### 👁️ **Level 20** - *Omnipotent* ### 👁️ **Level 20** - *Omnipotent*
- **XP Required**: 1900+ XP - **XP Required**: 44,520 XP
- **Description**: You are the ultimate master of pleasure and desire! - **Description**: You are the ultimate master of pleasure and desire!
- **Unlocks**:
- Omnipotent status (highest achievable)
- All features and privileges
- Exclusive omnipotent recognition
- Developer acknowledgment
- Infinite progression tracking
--- ---
## 🏆 Achievement Integration ## 🏆 Achievement Integration
### Level-Based Achievements ### Level-Based Achievements
- **Level Up** - Reach Level 5 (400+ XP) - **Lustful Awakening** - Reach Level 5 (82 XP)
- **XP Master** - Earn 500+ total XP (Level 6) - **Passionate Soul** - Earn 500+ total XP
- **Elite Status** - Reach Level 10 (900+ XP) - **Kinky Elite** - Reach Level 10 (751 XP)
- **Legendary** - Reach Level 14 (1300+ XP) - **Depraved Master** - Reach Level 12 (1,716 XP)
- **Omnipotent** - Reach Level 20 (1900+ XP)
### Progression Achievements ### Progression Achievements
- **First Steps** - Watch your first video - **First Taste** - Watch your first video
- **Early Bird** - Watch 10 videos - **Early Bird** - Watch 10 videos
- **Marathon Viewer** - Watch for 2+ hours total - **Marathon Viewer** - Watch for 2+ hours total
- **Playlist Curator** - Create 5 playlists - **Playlist Curator** - Create 5 playlists
- **Consistency King** - Maintain a 7-day streak - **Consistency King** - Maintain a 7-day streak
- **Video Collector** - Watch 100 different videos - **Desire Collector** - Watch 100 different videos
--- ---
## 📊 Progression Tips ## 📊 Progression Tips
### Efficient XP Earning ### Efficient XP Earning
1. **Consistent Daily Activity**: Maintain streaks for bonus achievements 1. **Consistent Video Watching**: 1 XP per 5 minutes of viewing in Cinema mode
2. **Complete Tasks**: Finish Quick Play tasks for maximum XP 2. **Complete Quick Play Sessions**: Task completion and time bonuses
3. **Watch Full Videos**: Reach 90% completion in Cinema mode 3. **Watch Full Videos**: Reach 90% completion for statistics tracking
4. **Engage with Scenarios**: Use webcam features for bonus XP 4. **Engage with All Game Modes**: Each mode contributes to total XP
5. **Take Photos**: Earn 2 XP per photo in scenario modes 5. **Stay Active**: XP is awarded continuously during active sessions
### Level Milestones ### Level Milestone Ranges
- **Levels 1-5**: Sexual awakening and building desires (500 XP) - **Levels 1-5**: Initial awakening and exploration (0-82 XP)
- **Levels 6-10**: Corruption and exploring kinks (500 XP) - **Levels 6-10**: Developing passion and addiction (133-751 XP)
- **Levels 11-15**: Embracing perversion and depravity (500 XP) - **Levels 11-15**: Advanced perversion and hedonism (1,137-5,844 XP)
- **Levels 16-20**: Transcendent mastery of carnal arts (400+ XP) - **Levels 16-20**: Transcendent mastery requiring dedication (8,777-44,520 XP)
--- ---
## 🔮 Future Expansions ## 🔮 Future Expansions
### Planned Features ### Planned Features
- **Level 25+**: Extended progression for dedicated users - **Extended Levels**: Higher level caps for dedicated users
- **Prestige System**: Reset levels for additional bonuses - **Achievement Expansion**: More varied and challenging achievements
- **Seasonal Events**: Temporary XP multipliers and special achievements - **XP Multiplier Events**: Special periods with bonus XP rates
- **Community Features**: Level-based social interactions - **Progress Analytics**: Detailed tracking of XP sources and trends
- **Custom Rewards**: Personalized unlocks based on play style - **Level Rewards**: Visual customizations and special features for high levels
### Level Cap Expansion ### System Scalability
The system is designed to easily extend beyond Level 20, with potential for: The exponential XP system is designed to accommodate:
- **Level 50**: Ultra-Legendary status - **Higher Level Caps**: Mathematical progression allows infinite scaling
- **Level 100**: Mythical achievements - **Balanced Progression**: Maintains challenge while rewarding dedication
- **Infinite Progression**: No level cap for ultimate dedication - **Achievement Integration**: New achievements can be easily added at any level
--- ---

0
feedback.txt Normal file
View File

View File

@ -99,6 +99,242 @@
height: 20px; height: 20px;
border-radius: 50%; border-radius: 50%;
cursor: pointer; cursor: pointer;
}
/* Grid Layout Styles */
.grid-mode-selector {
background: rgba(102, 126, 234, 0.15);
border: 2px solid #667eea;
border-radius: 10px;
padding: 1rem;
margin-bottom: 1rem;
}
.grid-container {
width: 100%;
height: 70vh;
background: #000;
border-radius: 10px;
border: 2px solid #667eea;
position: relative;
overflow: hidden;
}
.grid-container.single {
display: flex;
align-items: center;
justify-content: center;
}
.grid-container.grid-2x2 {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 2px;
}
.grid-container.grid-3x3 {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
gap: 2px;
}
.grid-cell {
position: relative;
background: #111;
border: 1px solid #333;
overflow: hidden;
display: flex;
flex-direction: column;
}
.grid-cell-image {
width: 100%;
height: 100%;
object-fit: contain;
opacity: 0;
transition: opacity 0.3s ease;
}
.grid-cell-image.visible {
opacity: 1;
}
.grid-cell-info {
position: absolute;
top: 5px;
left: 5px;
background: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 2px 6px;
border-radius: 3px;
font-size: 0.7rem;
z-index: 10;
}
.grid-cell-controls {
position: absolute;
top: 5px;
right: 5px;
display: flex;
gap: 2px;
z-index: 10;
}
.grid-cell-btn {
background: rgba(102, 126, 234, 0.8);
color: white;
border: none;
border-radius: 3px;
padding: 2px 4px;
cursor: pointer;
font-size: 0.7rem;
}
.grid-cell-btn:hover {
background: rgba(102, 126, 234, 1);
}
.grid-progress-container {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 3px;
background: rgba(0, 0, 0, 0.5);
z-index: 10;
}
.grid-progress-bar {
height: 100%;
background: #667eea;
width: 0%;
transition: width linear;
}
.grid-controls {
display: flex;
gap: 0.5rem;
margin-top: 1rem;
flex-wrap: wrap;
}
.grid-assignment {
margin-top: 1rem;
padding: 1rem;
background: rgba(0, 0, 0, 0.3);
border-radius: 10px;
}
.cell-assignment {
display: flex;
align-items: center;
gap: 1rem;
margin: 0.5rem 0;
}
.cell-assignment label {
min-width: 80px;
color: #ccc;
}
.cell-assignment select {
flex: 1;
padding: 0.25rem;
background: #333;
color: #fff;
border: 1px solid #667eea;
border-radius: 5px;
}
/* Fullscreen Grid Container */
.grid-slideshow-container {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: #000;
z-index: 1000;
flex-direction: column;
}
.grid-slideshow-display {
flex: 1;
width: 100%;
height: 100%;
position: relative;
}
.grid-slideshow-display .grid-container {
width: 100%;
height: 100%;
border: none;
border-radius: 0;
}
.grid-slideshow-display .grid-cell {
border: 1px solid #333;
}
.grid-slideshow-info {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 10px 15px;
border-radius: 8px;
font-size: 0.9rem;
z-index: 10;
min-width: 200px;
opacity: 0.9;
transition: opacity 0.3s ease;
}
.grid-slideshow-info:hover {
opacity: 1;
}
.grid-slideshow-controls {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 15px;
background: rgba(0, 0, 0, 0.8);
padding: 15px 25px;
border-radius: 50px;
z-index: 10;
opacity: 0.9;
transition: opacity 0.3s ease;
}
.grid-slideshow-controls:hover {
opacity: 1;
}
.grid-slideshow-controls button {
background: rgba(102, 126, 234, 0.8);
color: white;
border: none;
border-radius: 25px;
padding: 10px 20px;
cursor: pointer;
font-size: 0.9rem;
transition: background 0.3s ease;
}
.grid-slideshow-controls button:hover {
background: rgba(102, 126, 234, 1);
}
.grid-slideshow-controls button:disabled {
background: rgba(102, 126, 234, 0.3);
cursor: not-allowed;
-webkit-appearance: none; -webkit-appearance: none;
} }
@ -533,6 +769,50 @@
</div> </div>
</div> </div>
<!-- Grid Mode Selection -->
<div class="settings-panel">
<div class="settings-section">
<h3>🔲 Display Mode</h3>
<div class="setting-group">
<div class="setting-row">
<span class="setting-label">Layout Mode:</span>
<div class="setting-control">
<select id="displayMode" onchange="updateDisplayMode()">
<option value="single">Single Slideshow</option>
<option value="grid-2x2">2x2 Grid</option>
<option value="grid-3x3">3x3 Grid</option>
</select>
</div>
</div>
<!-- Grid View Container -->
<div id="gridView" style="display: none;">
<div class="grid-container single" id="gridContainer"></div>
<div class="grid-controls">
<button onclick="startGridSlideshow()" class="btn" id="startGridBtn">
▶️ Start Grid
</button>
<button onclick="pauseGridSlideshow()" class="btn" id="pauseGridBtn" disabled>
⏸️ Pause Grid
</button>
<button onclick="stopGridSlideshow()" class="btn" id="stopGridBtn" disabled>
⏹️ Stop Grid
</button>
<button onclick="nextGridAll()" class="btn" id="nextGridBtn">
⏭️ Next All
</button>
</div>
<div class="grid-assignment" id="gridAssignment">
<h4 style="color: #667eea; margin: 0 0 1rem 0;">📋 Slideshow Assignment</h4>
<div id="cellAssignments"></div>
</div>
</div>
</div>
</div>
</div>
<!-- Settings Panel --> <!-- Settings Panel -->
<div class="settings-panel"> <div class="settings-panel">
<!-- Timing Settings --> <!-- Timing Settings -->
@ -766,6 +1046,23 @@
</div> </div>
</div> </div>
<!-- Grid Slideshow Container (Fullscreen) -->
<div class="grid-slideshow-container" id="gridSlideshowContainer">
<div class="grid-slideshow-display" id="gridSlideshowDisplay"></div>
<div class="grid-slideshow-info" id="gridSlideshowInfo">
<div>Grid Mode: <span id="gridModeDisplay">2x2</span></div>
<div>Active Cells: <span id="activeCells">0</span></div>
<div>Status: <span id="gridSlideshowStatus">Ready</span></div>
</div>
<div class="grid-slideshow-controls">
<button onclick="pauseGridSlideshow()" id="gridPauseBtn">⏸️ Pause All</button>
<button onclick="nextGridAll()" id="gridNextBtn">⏭️ Next All</button>
<button onclick="stopGridSlideshow()" id="gridStopBtn">⏹️ Stop Grid</button>
</div>
</div>
<!-- Core Scripts --> <!-- Core Scripts -->
<script> <script>
// Only load Electron-specific scripts if in Electron environment // Only load Electron-specific scripts if in Electron environment
@ -821,6 +1118,511 @@
waveTime: 0 waveTime: 0
}; };
// Grid Slideshow Variables
let gridSlideshow = {
mode: 'single',
cells: [],
isPlaying: false,
isPaused: false,
configurations: {}
};
// GridCell Class
class GridCell {
constructor(index) {
this.index = index;
this.slideshow = null;
this.images = [];
this.currentIndex = 0;
this.timer = null;
this.element = null;
this.imageElement = null;
this.infoElement = null;
this.progressElement = null;
this.isPlaying = false;
// Copy current settings safely
this.settings = {
timingMode: currentSettings.timingMode,
duration: currentSettings.duration,
minDuration: currentSettings.minDuration,
maxDuration: currentSettings.maxDuration,
waveMin: currentSettings.waveMin,
waveMax: currentSettings.waveMax,
waveRate: currentSettings.waveRate,
transitionDuration: currentSettings.transitionDuration
};
console.log(`GridCell ${index} initialized with settings:`, this.settings);
}
initializeElement() {
this.element = document.createElement('div');
this.element.className = 'grid-cell';
this.element.innerHTML = `
<img class="grid-cell-image" alt="Grid Cell Image">
<div class="grid-cell-info">
<div>Cell ${this.index + 1}: <span class="cell-slideshow">Empty</span></div>
<div>Image: <span class="cell-current">0</span> / <span class="cell-total">0</span></div>
</div>
<div class="grid-cell-controls">
<button class="grid-cell-btn" onclick="pauseGridCell(${this.index})">⏸️</button>
<button class="grid-cell-btn" onclick="nextGridCell(${this.index})">⏭️</button>
</div>
<div class="grid-progress-container">
<div class="grid-progress-bar"></div>
</div>
`;
this.imageElement = this.element.querySelector('.grid-cell-image');
this.infoElement = this.element.querySelector('.grid-cell-info');
this.progressElement = this.element.querySelector('.grid-progress-bar');
return this.element;
}
async loadSlideshow(slideshow) {
console.log(`Cell ${this.index}: Loading slideshow:`, slideshow ? slideshow.name : 'null');
this.slideshow = slideshow;
if (slideshow) {
// Load images for this specific slideshow
this.images = await getGridCellImages(slideshow);
} else {
this.images = [];
}
console.log(`Cell ${this.index}: Loaded ${this.images.length} images`);
this.currentIndex = 0;
this.updateInfo();
this.displayCurrentImage();
}
updateInfo() {
if (this.infoElement) {
const slideshowSpan = this.infoElement.querySelector('.cell-slideshow');
const currentSpan = this.infoElement.querySelector('.cell-current');
const totalSpan = this.infoElement.querySelector('.cell-total');
if (slideshowSpan) slideshowSpan.textContent = this.slideshow ? this.slideshow.name : 'Empty';
if (currentSpan) currentSpan.textContent = this.images.length > 0 ? this.currentIndex + 1 : 0;
if (totalSpan) totalSpan.textContent = this.images.length;
}
}
displayCurrentImage() {
if (this.images.length === 0 || !this.imageElement) return;
const imageData = this.images[this.currentIndex];
console.log(`Cell ${this.index}: Image data structure:`, imageData);
let imageSrc;
if (typeof imageData === 'string') {
imageSrc = imageData;
} else {
// Try different possible path properties in order of preference
imageSrc = imageData.cachedPath || imageData.fullPath || imageData.path || imageData.src || imageData.dataURL;
}
console.log(`Cell ${this.index}: Using image src: ${imageSrc}`);
if (!imageSrc) {
console.error(`Cell ${this.index}: No valid image source found in:`, imageData);
return;
}
this.imageElement.style.opacity = '0';
setTimeout(() => {
this.imageElement.src = imageSrc;
this.imageElement.style.opacity = '1';
this.imageElement.classList.add('visible');
}, this.settings.transitionDuration / 2);
}
nextImage() {
if (this.images.length === 0) return;
this.currentIndex = (this.currentIndex + 1) % this.images.length;
this.updateInfo();
this.displayCurrentImage();
}
startTimer() {
console.log(`Cell ${this.index}: Starting timer`);
if (this.timer) clearTimeout(this.timer);
const duration = this.calculateDuration();
console.log(`Cell ${this.index}: Duration = ${duration}ms`);
this.updateProgress(duration);
this.timer = setTimeout(() => {
console.log(`Cell ${this.index}: Timer fired, advancing image`);
this.nextImage();
if (this.isPlaying) {
this.startTimer();
}
}, duration);
}
calculateDuration() {
switch (this.settings.timingMode) {
case 'random':
return Math.random() * (this.settings.maxDuration - this.settings.minDuration) + this.settings.minDuration;
case 'wave':
const wavePosition = Date.now() / 1000 / this.settings.waveRate;
const waveValue = (Math.sin(wavePosition) + 1) / 2;
return this.settings.waveMin + (this.settings.waveMax - this.settings.waveMin) * waveValue;
default:
return this.settings.duration;
}
}
updateProgress(duration) {
if (!this.progressElement) return;
this.progressElement.style.transition = 'none';
this.progressElement.style.width = '0%';
setTimeout(() => {
this.progressElement.style.transition = `width ${duration}ms linear`;
this.progressElement.style.width = '100%';
}, 50);
}
pause() {
this.isPlaying = false;
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
}
resume() {
this.isPlaying = true;
this.startTimer();
}
stop() {
this.isPlaying = false;
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
this.currentIndex = 0;
this.updateInfo();
if (this.progressElement) {
this.progressElement.style.width = '0%';
}
}
}
// Grid Management Functions
function updateDisplayMode() {
const mode = document.getElementById('displayMode').value;
const gridView = document.getElementById('gridView');
if (mode === 'single') {
gridView.style.display = 'none';
stopGridSlideshow();
} else {
gridView.style.display = 'block';
setupGridLayout(mode);
}
gridSlideshow.mode = mode;
}
function setupGridLayout(mode) {
const gridContainer = document.getElementById('gridContainer');
// Clear existing grid
gridContainer.innerHTML = '';
gridSlideshow.cells = [];
// Set grid class
gridContainer.className = `grid-container ${mode}`;
// Create cells based on mode
let cellCount = 1;
switch (mode) {
case 'grid-2x2':
cellCount = 4;
break;
case 'grid-3x3':
cellCount = 9;
break;
default:
cellCount = 1;
}
// Create grid cells
for (let i = 0; i < cellCount; i++) {
const cell = new GridCell(i);
gridSlideshow.cells.push(cell);
const cellElement = cell.initializeElement();
gridContainer.appendChild(cellElement);
}
updateCellAssignments();
updateGridControls();
}
function updateCellAssignments() {
const container = document.getElementById('cellAssignments');
if (!container) return;
container.innerHTML = '';
console.log('📋 Updating cell assignments, available slideshows:', Object.keys(savedSlideshows));
gridSlideshow.cells.forEach((cell, index) => {
const div = document.createElement('div');
div.className = 'cell-assignment';
const select = document.createElement('select');
select.innerHTML = '<option value="">Select slideshow...</option>';
Object.keys(savedSlideshows).forEach(name => {
const option = document.createElement('option');
option.value = name;
option.textContent = `${name} (${savedSlideshows[name].images?.length || 0} images)`;
select.appendChild(option);
});
select.onchange = async () => {
console.log(`Assigning slideshow "${select.value}" to cell ${index}`);
if (select.value) {
await cell.loadSlideshow(savedSlideshows[select.value]);
} else {
await cell.loadSlideshow(null);
}
};
div.innerHTML = `<label>Cell ${index + 1}:</label>`;
div.appendChild(select);
container.appendChild(div);
});
}
async function startGridSlideshow() {
console.log('🟢 Starting grid slideshow...');
console.log('Grid cells:', gridSlideshow.cells.length);
if (gridSlideshow.cells.length === 0) {
alert('No grid cells configured');
return;
}
// Enter fullscreen grid mode
enterGridFullscreen();
gridSlideshow.isPlaying = true;
gridSlideshow.isPaused = false;
let activeCellCount = 0;
gridSlideshow.cells.forEach((cell, index) => {
console.log(`Cell ${index}: ${cell.images.length} images`);
if (cell.images.length > 0) {
console.log(`Starting cell ${index}`);
cell.isPlaying = true;
cell.startTimer();
activeCellCount++;
} else {
console.log(`Cell ${index} has no images, skipping`);
}
});
// Update fullscreen info
document.getElementById('gridModeDisplay').textContent = gridSlideshow.mode;
document.getElementById('activeCells').textContent = activeCellCount;
document.getElementById('gridSlideshowStatus').textContent = 'Playing';
updateGridControls();
console.log('✅ Grid slideshow start complete');
}
function pauseGridSlideshow() {
if (gridSlideshow.isPaused) {
resumeGridSlideshow();
return;
}
gridSlideshow.isPaused = true;
gridSlideshow.cells.forEach(cell => {
cell.pause();
});
updateGridControls();
}
function resumeGridSlideshow() {
gridSlideshow.isPaused = false;
gridSlideshow.cells.forEach(cell => {
if (cell.images.length > 0) {
cell.resume();
}
});
updateGridControls();
}
function stopGridSlideshow() {
gridSlideshow.isPlaying = false;
gridSlideshow.isPaused = false;
gridSlideshow.cells.forEach(cell => {
cell.stop();
});
// Exit fullscreen mode
exitGridFullscreen();
// Update status
const gridStatus = document.getElementById('gridSlideshowStatus');
if (gridStatus) {
gridStatus.textContent = 'Stopped';
}
updateGridControls();
console.log('🔲 Grid slideshow stopped');
}
// Fullscreen grid control functions
function pauseGridSlideshow() {
if (!gridSlideshow.isPlaying) return;
gridSlideshow.isPaused = !gridSlideshow.isPaused;
gridSlideshow.cells.forEach(cell => {
if (gridSlideshow.isPaused) {
cell.pause();
} else {
cell.resume();
}
});
// Update status
const gridStatus = document.getElementById('gridSlideshowStatus');
if (gridStatus) {
gridStatus.textContent = gridSlideshow.isPaused ? 'Paused' : 'Playing';
}
updateGridControls();
console.log('⏸️ Grid slideshow', gridSlideshow.isPaused ? 'paused' : 'resumed');
}
function nextGridAll() {
if (!gridSlideshow.isPlaying) return;
gridSlideshow.cells.forEach(cell => {
if (cell.images.length > 0) {
cell.next();
}
});
console.log('⏭️ All grid cells advanced to next image');
}
function nextGridAll() {
gridSlideshow.cells.forEach(cell => {
if (cell.images.length > 0) {
cell.nextImage();
}
});
}
function pauseGridCell(cellIndex) {
const cell = gridSlideshow.cells[cellIndex];
if (cell) {
if (cell.isPlaying) {
cell.pause();
} else {
cell.resume();
}
}
}
function nextGridCell(cellIndex) {
const cell = gridSlideshow.cells[cellIndex];
if (cell && cell.images.length > 0) {
cell.nextImage();
}
}
function updateGridControls() {
const startBtn = document.getElementById('startGridBtn');
const pauseBtn = document.getElementById('pauseGridBtn');
const stopBtn = document.getElementById('stopGridBtn');
if (startBtn && pauseBtn && stopBtn) {
if (gridSlideshow.isPlaying) {
startBtn.disabled = true;
pauseBtn.disabled = false;
pauseBtn.textContent = gridSlideshow.isPaused ? '▶️ Resume Grid' : '⏸️ Pause Grid';
stopBtn.disabled = false;
} else {
startBtn.disabled = false;
pauseBtn.disabled = true;
pauseBtn.textContent = '⏸️ Pause Grid';
stopBtn.disabled = true;
}
}
// Update fullscreen controls if visible
const gridPauseBtn = document.getElementById('gridPauseBtn');
const gridStopBtn = document.getElementById('gridStopBtn');
if (gridPauseBtn && gridStopBtn) {
if (gridSlideshow.isPlaying) {
gridPauseBtn.disabled = false;
gridPauseBtn.textContent = gridSlideshow.isPaused ? '▶️ Resume All' : '⏸️ Pause All';
gridStopBtn.disabled = false;
} else {
gridPauseBtn.disabled = true;
gridPauseBtn.textContent = '⏸️ Pause All';
gridStopBtn.disabled = true;
}
}
}
function enterGridFullscreen() {
console.log('🔲 Entering grid fullscreen mode');
// Hide main content
document.querySelector('.main-content').style.display = 'none';
// Show grid fullscreen container
document.getElementById('gridSlideshowContainer').style.display = 'flex';
// Move grid container to fullscreen display
const gridContainer = document.getElementById('gridContainer');
const fullscreenDisplay = document.getElementById('gridSlideshowDisplay');
if (gridContainer && fullscreenDisplay) {
fullscreenDisplay.appendChild(gridContainer);
}
}
function exitGridFullscreen() {
console.log('🔲 Exiting grid fullscreen mode');
// Hide grid fullscreen container
document.getElementById('gridSlideshowContainer').style.display = 'none';
// Show main content
document.querySelector('.main-content').style.display = 'block';
// Move grid container back to settings
const gridContainer = document.getElementById('gridContainer');
const gridView = document.getElementById('gridView');
if (gridContainer && gridView) {
// Find the original position (after the controls)
const gridControls = gridView.querySelector('.grid-controls');
if (gridControls && gridControls.nextElementSibling) {
gridView.insertBefore(gridContainer, gridControls.nextElementSibling);
} else {
gridView.appendChild(gridContainer);
}
}
}
// Initialize Hypno Gallery // Initialize Hypno Gallery
async function initializeHypnoGallery() { async function initializeHypnoGallery() {
console.log('🌀 Initializing Hypno Gallery...'); console.log('🌀 Initializing Hypno Gallery...');
@ -1929,6 +2731,10 @@
console.log('📋 No saved slideshows found, initialized empty object'); console.log('📋 No saved slideshows found, initialized empty object');
} }
updateSlideshowsList(); updateSlideshowsList();
// Refresh grid cell assignments if in grid mode
if (gridSlideshow.mode !== 'single' && gridSlideshow.cells.length > 0) {
updateCellAssignments();
}
} catch (error) { } catch (error) {
console.error('❌ Error loading slideshows:', error); console.error('❌ Error loading slideshows:', error);
savedSlideshows = {}; savedSlideshows = {};
@ -1939,6 +2745,10 @@
try { try {
localStorage.setItem('hypnoGallerySlideshows', JSON.stringify(savedSlideshows)); localStorage.setItem('hypnoGallerySlideshows', JSON.stringify(savedSlideshows));
console.log('💾 Slideshows saved to storage'); console.log('💾 Slideshows saved to storage');
// Refresh grid cell assignments if in grid mode
if (gridSlideshow.mode !== 'single' && gridSlideshow.cells.length > 0) {
updateCellAssignments();
}
} catch (error) { } catch (error) {
console.error('❌ Error saving slideshows:', error); console.error('❌ Error saving slideshows:', error);
} }
@ -2251,6 +3061,11 @@
updateCurrentSessionDisplay(); updateCurrentSessionDisplay();
updateSlideshowDetails(); updateSlideshowDetails();
// Refresh grid cell assignments if in grid mode
if (gridSlideshow.mode !== 'single' && gridSlideshow.cells.length > 0) {
updateCellAssignments();
}
console.log('📂 Auto-loaded slideshow:', name); console.log('📂 Auto-loaded slideshow:', name);
} }
@ -2976,6 +3791,44 @@ ${invalidDirs.length > 0 ? `\nInvalid directories:\n${invalidDirs.join('\n')}` :
return images; return images;
} }
// Grid-specific image loading function for individual cells
async function getGridCellImages(slideshow) {
let images = [];
console.log(`🔲 Loading images for grid cell slideshow: ${slideshow.name}`);
// Load images from slideshow-specific directories
const directories = slideshow.directories || [];
console.log(`📁 Slideshow directories: ${directories.length}`);
for (const dir of directories) {
const dirPath = typeof dir === 'string' ? dir : dir.path;
try {
const dirImages = await loadImagesFromDirectory(dirPath);
images.push(...dirImages);
console.log(`📁 Grid cell loaded ${dirImages.length} images from: ${dirPath}`);
} catch (error) {
console.error(`❌ Grid cell error loading directory ${dirPath}:`, error);
}
}
// Include captured photos if enabled
if (slideshow.includeCapturedPhotos) {
const capturedPhotos = getCapturedPhotos();
images.push(...capturedPhotos);
console.log(`📷 Grid cell added ${capturedPhotos.length} captured photos`);
}
// Fallback to main library if no directories configured
if (images.length === 0) {
console.log('📚 Grid cell using main image library as fallback');
images = [...imageLibrary];
}
console.log(`🖼️ Grid cell total images: ${images.length}`);
return images;
}
async function loadImagesFromDirectory(directoryPath) { async function loadImagesFromDirectory(directoryPath) {
// Load images from a directory recursively using the main process function // Load images from a directory recursively using the main process function
console.log(`🔍 Starting recursive image scan of: ${directoryPath}`); console.log(`🔍 Starting recursive image scan of: ${directoryPath}`);

View File

@ -32,6 +32,7 @@ copy training-academy.html "%OUTPUT_DIR%\"
copy porn-cinema.html "%OUTPUT_DIR%\" copy porn-cinema.html "%OUTPUT_DIR%\"
copy player-stats.html "%OUTPUT_DIR%\" copy player-stats.html "%OUTPUT_DIR%\"
copy user-profile.html "%OUTPUT_DIR%\" copy user-profile.html "%OUTPUT_DIR%\"
copy hypno-gallery.html "%OUTPUT_DIR%\"
copy package.json "%OUTPUT_DIR%\" copy package.json "%OUTPUT_DIR%\"
:: Copy documentation :: Copy documentation