// Main application logic let currentTelemetryData = null; let currentPlaybackSequence = null; let playbackInterval = null; let currentTick = 0; let canvas, ctx; // Initialize upload form document.addEventListener('DOMContentLoaded', () => { const fileInput = document.getElementById('report-file'); const fileInfo = document.getElementById('file-info'); const fileName = document.getElementById('file-name'); const fileSize = document.getElementById('file-size'); const analyzeBtn = document.getElementById('analyze-btn'); const uploadForm = document.getElementById('upload-form'); // Handle file selection fileInput.addEventListener('change', (e) => { if (e.target.files.length > 0) { const file = e.target.files[0]; fileName.textContent = file.name; fileSize.textContent = `(${(file.size / 1024).toFixed(1)} KB)`; fileInfo.classList.remove('hidden'); analyzeBtn.classList.remove('hidden'); } else { fileInfo.classList.add('hidden'); analyzeBtn.classList.add('hidden'); } } function updateStatsOverview() { if (!currentTelemetryData?.sequences) return; const sequences = currentTelemetryData.sequences; let totalShots = 0; let totalHits = 0; let totalSuspicion = 0; sequences.forEach(seq => { const stats = seq.sequence_stats || {}; totalShots += stats.total_shots || 0; totalHits += stats.hits || 0; totalSuspicion += calculateSuspicionScore(stats); }); const avgAccuracy = totalShots > 0 ? (totalHits / totalShots) : 0; const avgSuspicion = sequences.length > 0 ? (totalSuspicion / sequences.length) : 0; document.getElementById('total-sequences').textContent = sequences.length; document.getElementById('avg-accuracy').textContent = Math.round(avgAccuracy * 100) + '%'; document.getElementById('suspicion-score').textContent = Math.round(avgSuspicion); document.getElementById('total-shots').textContent = totalShots; } function initializeCharts() { if (!currentTelemetryData?.sequences) return; const sequences = currentTelemetryData.sequences; const accuracyData = sequences.map(seq => Math.round((seq.sequence_stats?.accuracy || 0) * 100)); const suspicionData = sequences.map((seq, index) => ({ x: index, y: calculateSuspicionScore(seq.sequence_stats || {}) })); // Accuracy distribution chart const accuracyCtx = document.getElementById('accuracy-chart').getContext('2d'); new Chart(accuracyCtx, { type: 'bar', data: { labels: accuracyData.map((_, i) => `Seq ${i + 1}`), datasets: [{ label: 'Accuracy %', data: accuracyData, backgroundColor: 'rgba(59, 130, 246, 0.5)', borderColor: 'rgba(59, 130, 246, 1)', borderWidth: 1 }] }, options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, max: 100, ticks: { color: '#9ca3af' }, grid: { color: '#374151' } }, x: { ticks: { color: '#9ca3af' }, grid: { color: '#374151' } } } } }); // Suspicion timeline chart const suspicionCtx = document.getElementById('suspicion-chart').getContext('2d'); new Chart(suspicionCtx, { type: 'line', data: { datasets: [{ label: 'Suspicion Score', data: suspicionData, backgroundColor: 'rgba(239, 68, 68, 0.1)', borderColor: 'rgba(239, 68, 68, 1)', borderWidth: 2, tension: 0.4, fill: true }] }, options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, max: 100, ticks: { color: '#9ca3af' }, grid: { color: '#374151' } }, x: { ticks: { color: '#9ca3af' }, grid: { color: '#374151' } } } } }); } function sortSequences(sortBy) { if (!currentTelemetryData?.sequences) return; const container = document.getElementById('sequences-container'); const sequences = [...currentTelemetryData.sequences]; if (sortBy === 'accuracy') { sequences.sort((a, b) => (b.sequence_stats?.accuracy || 0) - (a.sequence_stats?.accuracy || 0)); } else if (sortBy === 'suspicion') { sequences.sort((a, b) => calculateSuspicionScore(b.sequence_stats || {}) - calculateSuspicionScore(a.sequence_stats || {})); } currentTelemetryData.sequences = sequences; renderSequences(); } function exportReport() { if (!currentTelemetryData) { alert('No data to export'); return; } const reportData = { player_name: currentTelemetryData.player_name, steam_id: currentTelemetryData.steam_id, timestamp: currentTelemetryData.timestamp, summary: { total_sequences: currentTelemetryData.sequences.length, avg_accuracy: document.getElementById('avg-accuracy').textContent, suspicion_score: document.getElementById('suspicion-score').textContent, total_shots: document.getElementById('total-shots').textContent }, sequences: currentTelemetryData.sequences.map(seq => ({ sequence_id: seq.sequence_id, accuracy: seq.sequence_stats?.accuracy || 0, hits: seq.sequence_stats?.hits || 0, total_shots: seq.sequence_stats?.total_shots || 0, suspicion_score: calculateSuspicionScore(seq.sequence_stats || {}) })) }; const blob = new Blob([JSON.stringify(reportData, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `aimbot-report-${Date.now()}.json`; a.click(); URL.revokeObjectURL(url); } function resetAnalysis() { currentTelemetryData = null; currentPlaybackSequence = null; stopPlayback(); document.getElementById('upload-section').classList.remove('hidden'); document.getElementById('dashboard').classList.add('hidden'); document.getElementById('report-file').value = ''; document.getElementById('file-info').classList.add('hidden'); // Clear charts Chart.getChart('accuracy-chart')?.destroy(); Chart.getChart('suspicion-chart')?.destroy(); } function showHelp() { document.getElementById('help-modal').classList.remove('hidden'); } function closeHelp() { document.getElementById('help-modal').classList.add('hidden'); } function showSettings() { alert('Settings panel coming soon!'); } function toggleFullscreen() { const canvas = document.getElementById('playback-canvas'); if (!document.fullscreenElement) { canvas.requestFullscreen(); } else { document.exitFullscreen(); } } ); // Handle form submission uploadForm.addEventListener('submit', (e) => { e.preventDefault(); if (fileInput.files.length === 0) return; const file = fileInput.files[0]; const reader = new FileReader(); analyzeBtn.disabled = true; analyzeBtn.innerHTML = 'Analyzing... '; window.feather.replace(); reader.onload = (e) => { try { const telemetryData = JSON.parse(e.target.result); initializeApp(telemetryData); document.getElementById('upload-section').classList.add('hidden'); document.getElementById('dashboard').classList.remove('hidden'); window.scrollTo({ top: 0, behavior: 'smooth' }); } catch (error) { alert('Error parsing report file. Please ensure it is valid JSON.'); console.error(error); } finally { analyzeBtn.disabled = false; analyzeBtn.innerHTML = 'Analyze Report '; window.feather.replace(); } }; reader.readAsText(file); }); }); function initializeApp(telemetryData) { try { if (!telemetryData || typeof telemetryData !== 'object') { throw new Error('Invalid telemetry data'); } currentTelemetryData = telemetryData; // Initialize canvas canvas = document.getElementById('playback-canvas'); ctx = canvas.getContext('2d'); resizeCanvas(); window.addEventListener('resize', resizeCanvas); // Render player stats updatePlayerStats(); // Update stats overview updateStatsOverview(); // Render sequences renderSequences(); // Initialize charts initializeCharts(); } catch (error) { console.error('Error initializing app:', error); alert('Error initializing application. Please check the report file.'); } } function resizeCanvas() { const container = canvas.parentElement; canvas.width = container.clientWidth; canvas.height = container.clientHeight; } function updatePlayerStats() { const playerStats = document.querySelector('custom-player-stats'); if (playerStats) { playerStats.setAttribute('name', currentTelemetryData.player_name); playerStats.setAttribute('steam-id', currentTelemetryData.steam_id); playerStats.setAttribute('timestamp', new Date(currentTelemetryData.timestamp * 1000).toLocaleString()); playerStats.setAttribute('sequence-count', currentTelemetryData.sequences.length.toString()); } } function renderSequences() { const container = document.getElementById('sequences-container'); container.innerHTML = ''; if (!currentTelemetryData?.sequences) return; currentTelemetryData.sequences.forEach((sequence, index) => { const stats = sequence?.sequence_stats || {}; const accuracy = stats?.accuracy || 0; const hits = stats.hits || 0; const totalShots = stats.total_shots || 0; const seqElement = document.createElement('div'); seqElement.className = 'sequence-card bg-gray-700 rounded-lg p-4 cursor-pointer hover:bg-gray-600'; seqElement.innerHTML = `
${sequence.sequence_id || 'Unknown ID'}