import { useState, useEffect, useRef } from 'react'; import { Core } from '@esengine/ecs-framework'; import { Activity, BarChart3, Clock, Cpu, RefreshCw, Pause, Play } from 'lucide-react'; import '../styles/ProfilerPanel.css'; interface SystemPerformanceData { name: string; executionTime: number; entityCount: number; averageTime: number; minTime: number; maxTime: number; percentage: number; } export function ProfilerPanel() { const [systems, setSystems] = useState([]); const [totalFrameTime, setTotalFrameTime] = useState(0); const [isPaused, setIsPaused] = useState(false); const [sortBy, setSortBy] = useState<'time' | 'average' | 'name'>('time'); const animationRef = useRef(); useEffect(() => { const updateProfilerData = () => { if (isPaused) { animationRef.current = requestAnimationFrame(updateProfilerData); return; } const coreInstance = Core.Instance; if (!coreInstance || !coreInstance._performanceMonitor?.isEnabled) { animationRef.current = requestAnimationFrame(updateProfilerData); return; } const performanceMonitor = coreInstance._performanceMonitor; const systemDataMap = performanceMonitor.getAllSystemData(); const systemStatsMap = performanceMonitor.getAllSystemStats(); const systemsData: SystemPerformanceData[] = []; let total = 0; for (const [name, data] of systemDataMap.entries()) { const stats = systemStatsMap.get(name); if (stats) { systemsData.push({ name, executionTime: data.executionTime, entityCount: data.entityCount, averageTime: stats.averageTime, minTime: stats.minTime, maxTime: stats.maxTime, percentage: 0 }); total += data.executionTime; } } // Calculate percentages systemsData.forEach(system => { system.percentage = total > 0 ? (system.executionTime / total) * 100 : 0; }); // Sort systems systemsData.sort((a, b) => { switch (sortBy) { case 'time': return b.executionTime - a.executionTime; case 'average': return b.averageTime - a.averageTime; case 'name': return a.name.localeCompare(b.name); default: return 0; } }); setSystems(systemsData); setTotalFrameTime(total); animationRef.current = requestAnimationFrame(updateProfilerData); }; animationRef.current = requestAnimationFrame(updateProfilerData); return () => { if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, [isPaused, sortBy]); const handleReset = () => { const coreInstance = Core.Instance; if (coreInstance && coreInstance._performanceMonitor) { coreInstance._performanceMonitor.reset(); } }; const fps = totalFrameTime > 0 ? Math.round(1000 / totalFrameTime) : 0; const targetFrameTime = 16.67; // 60 FPS const isOverBudget = totalFrameTime > targetFrameTime; return (
Frame: {totalFrameTime.toFixed(2)}ms
FPS: {fps}
Systems: {systems.length}
{systems.length === 0 ? (

No performance data available

Make sure Core debug mode is enabled and systems are running

) : (
{systems.map((system, index) => (
#{index + 1} {system.name} {system.entityCount > 0 && ( ({system.entityCount} entities) )}
{system.executionTime.toFixed(2)}ms {system.percentage.toFixed(1)}%
targetFrameTime ? 'var(--color-danger)' : system.executionTime > targetFrameTime * 0.5 ? 'var(--color-warning)' : 'var(--color-success)' }} />
Avg: {system.averageTime.toFixed(2)}ms
Min: {system.minTime.toFixed(2)}ms
Max: {system.maxTime.toFixed(2)}ms
))}
)}
Good (<8ms)
Warning (8-16ms)
Critical (>16ms)
); }