training-academy/docs/GAME_STATS_PANEL_FIX.md

6.9 KiB

Game Stats Panel Preservation - Implementation Guide

Problem

Interactive tasks that modify the sidebar can destroy the game stats panel, causing stats (XP, level, session time) to disappear during gameplay.

Root Cause

Tasks that use sidebar.innerHTML = ... or container.innerHTML = ... to inject UI elements destroy all existing sidebar children, including the game stats panel.

Solution Pattern

NEVER replace sidebar innerHTML. Always use specific elements for task UI.


Step-by-Step Fix for Any Interactive Task

1. Identify the Task Type

Check src/features/tasks/interactiveTaskManager.js for the task handler (e.g., createEdgeTask, createRhythmTask, createVideoStartTask, etc.)

2. Check for Sidebar Replacement

Look for patterns like:

// ❌ BAD - Destroys game stats panel
sidebar.innerHTML = `<div>...</div>`;
container.innerHTML = `<div class="sidebar-content">...</div>`;

3. Use Sidebar Timer Elements Instead

The campaign sidebar has these persistent elements:

  • #sidebar-countdown-timer - Wrapper div (show/hide with display: block/none)
  • #sidebar-countdown-display - Time text element (update with .textContent)
  • #game-stats-panel - Stats panel (must always exist, never destroy)
// ✅ GOOD - Preserves game stats panel
const sidebarTimer = document.getElementById('sidebar-countdown-timer');
const sidebarDisplay = document.getElementById('sidebar-countdown-display');

if (sidebarTimer) {
    sidebarTimer.style.display = 'block';
}

if (sidebarDisplay) {
    sidebarDisplay.textContent = `${mins}:${secs.toString().padStart(2, '0')}`;
}

4. Add Logging for Debugging

When showing/hiding sidebar elements, add console logs to verify game stats panel persists:

const gameStatsPanel = document.getElementById('game-stats-panel');
console.log('🎯 TASK START - Stats panel element:', gameStatsPanel);
console.log('🎯 TASK START - Stats panel display BEFORE:', gameStatsPanel?.style.display);

// Show sidebar timer
if (sidebarTimer) {
    sidebarTimer.style.display = 'block';
}

console.log('🎯 TASK START - Stats panel display AFTER:', gameStatsPanel?.style.display);

5. Hide Timer on Task Complete

Always hide the sidebar timer when task completes:

if (timeRemaining <= 0) {
    clearInterval(timerInterval);
    
    // Hide sidebar countdown timer
    const sidebarTimer = document.getElementById('sidebar-countdown-timer');
    if (sidebarTimer) {
        sidebarTimer.style.display = 'none';
    }
    
    task.completed = true;
    // ... rest of completion logic
}

Task-Specific Examples

Edge Task (Level 1)

File: interactiveTaskManager.js ~line 4660

Fixed Pattern:

// Don't create inline timer in HTML
// Use sidebar timer instead
const sidebarTimer = document.getElementById('sidebar-countdown-timer');
const sidebarDisplay = document.getElementById('sidebar-countdown-display');

if (sidebarTimer) sidebarTimer.style.display = 'block';

// Update timer in interval
timerInterval = setInterval(() => {
    timeRemaining--;
    const mins = Math.floor(timeRemaining / 60);
    const secs = timeRemaining % 60;
    
    if (sidebarDisplay) {
        sidebarDisplay.textContent = `${mins}:${secs.toString().padStart(2, '0')}`;
    }
    
    if (timeRemaining <= 0) {
        if (sidebarTimer) sidebarTimer.style.display = 'none';
        // ... completion logic
    }
}, 1000);

Rhythm Task (Level 2)

File: interactiveTaskManager.js ~line 4818

Issue: Was using sidebar.innerHTML = ... which destroyed game stats

Fixed Pattern:

// Don't do this:
// sidebar.innerHTML = `<div>Timer HTML</div>`;

// Do this instead:
const sidebarTimer = document.getElementById('sidebar-countdown-timer');
const sidebarDisplay = document.getElementById('sidebar-countdown-display');

if (sidebarTimer) sidebarTimer.style.display = 'block';
if (sidebarDisplay) sidebarDisplay.textContent = timeString;

Video Start Task (Level 3)

File: interactiveTaskManager.js - Need to check implementation

Pattern to Apply:

  1. Find createVideoStartTask function
  2. Look for any sidebar.innerHTML or container.innerHTML patterns
  3. Replace with sidebar timer element usage
  4. Add logging to verify stats panel persists
  5. Ensure timer hides on completion

Verification Checklist

When implementing the fix for any task:

  • Task does NOT use sidebar.innerHTML = ...
  • Task does NOT use container.innerHTML = ... that affects sidebar
  • Task uses #sidebar-countdown-timer and #sidebar-countdown-display elements
  • Task shows timer: sidebarTimer.style.display = 'block'
  • Task updates display: sidebarDisplay.textContent = timeString
  • Task hides timer on complete: sidebarTimer.style.display = 'none'
  • Logging added to track game stats panel visibility
  • Tested in-game to verify stats panel stays visible throughout task

Common Task Types to Fix

  1. video-start - Video playback with timer
  2. tag-files - File tagging interface
  3. slideshow - Image slideshow with timer
  4. dual-video - Dual video display
  5. quad-video - Quad video display
  6. webcam-mirror - Webcam display tasks
  7. Any task with duration or showTimer: true params

Files Involved

  • Task Implementation: src/features/tasks/interactiveTaskManager.js
  • Sidebar HTML: campaign.html (lines ~1270-1290)
  • XP Display Update: campaign.html (lines ~6815-6825)
  • Level Start Logic: campaign.html (lines ~4129-4137)

Reference: Sidebar Structure in campaign.html

<div id="campaign-sidebar" class="campaign-sidebar">
    <!-- Game Stats Panel - MUST ALWAYS EXIST -->
    <div id="game-stats-panel" class="game-stats-panel" style="display: block;">
        <div class="stat-item">
            <span class="stat-label">XP:</span>
            <span id="sidebar-current-xp" class="stat-value">0</span>
        </div>
        <div class="stat-item">
            <span class="stat-label">Session:</span>
            <span id="sidebar-session-time" class="stat-value">0:00</span>
        </div>
        <div class="stat-item">
            <span class="stat-label">Level:</span>
            <span id="sidebar-current-level" class="stat-value">1</span>
        </div>
    </div>

    <!-- Timer Panel - Show/hide as needed -->
    <div id="sidebar-countdown-timer" style="display: none;">
        <div class="timer-label">Time Remaining:</div>
        <div id="sidebar-countdown-display" class="timer-display">0:00</div>
    </div>
</div>

Key Takeaway

If your task has a timer and shows it in the sidebar:

  1. Use #sidebar-countdown-timer (show/hide wrapper)
  2. Use #sidebar-countdown-display (update text content)
  3. NEVER replace sidebar.innerHTML
  4. Always hide timer on task completion

This preserves the game stats panel and prevents the "disappearing stats" bug.