/** * AUTONOMOUS VISUAL ENGINE V6 - REAL DATA ANALYST CALCULATIONS * All values computed from actual data - no random/placeholder values */ import React, { useMemo, Component, ReactNode, CSSProperties } from 'react'; import { AreaChart, Area, BarChart, Bar, ScatterChart, Scatter, PieChart, Pie, LineChart, Line, RadialBarChart, RadialBar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell } from 'recharts'; // Error Boundary class ChartErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean }> { constructor(props: any) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError() { return { hasError: true }; } render() { return this.state.hasError ?
⚠️ Chart Error
: this.props.children; } } // Theme interface Theme { bg: string; card: string; text: string; muted: string; border: string; grid: string; success: string; danger: string; } const getTheme = (isDark: boolean): Theme => isDark ? { bg: '#0f172a', card: 'rgba(15, 23, 42, 0.85)', text: '#f1f5f9', muted: '#64748b', border: 'rgba(255,255,255,0.1)', grid: 'rgba(255,255,255,0.08)', success: '#22c55e', danger: '#ef4444' } : { bg: '#f8fafc', card: 'rgba(255,255,255,0.95)', text: '#0f172a', muted: '#64748b', border: 'rgba(0,0,0,0.08)', grid: 'rgba(0,0,0,0.06)', success: '#16a34a', danger: '#dc2626' }; // Color Themes (keyword-based) const THEMES: Record = { finance: ['#7c3aed', '#8b5cf6', '#a78bfa', '#3b82f6', '#0ea5e9', '#14b8a6'], activity: ['#f97316', '#fb923c', '#fdba74', '#ef4444', '#f59e0b', '#eab308'], health: ['#14b8a6', '#2dd4bf', '#5eead4', '#22c55e', '#10b981', '#06b6d4'], default: ['#14b8a6', '#0ea5e9', '#8b5cf6', '#f59e0b', '#ef4444', '#ec4899'] }; function detectTheme(data: any[], palette?: any): string[] { if (palette?.primary?.length) return [...palette.primary, ...(palette.secondary || [])]; const t = JSON.stringify(data).toLowerCase(); if (/revenue|profit|sales|cost|amount|price/.test(t)) return THEMES.finance; if (/activity|user|click|session/.test(t)) return THEMES.activity; if (/health|patient|medical/.test(t)) return THEMES.health; return THEMES.default; } // ============ REAL DATA ANALYST CALCULATIONS ============ interface DataStats { count: number; dateRange: string; dateRangeDays: number; numericColCount: number; catColCount: number; } interface MetricCalc { name: string; total: number; mean: number; median: number; std: number; min: number; max: number; trend: number; // % change (first half vs second half) trendDirection: 'up' | 'down' | 'stable'; outlierCount: number; } interface CategoryCalc { name: string; value: number; percent: number; rank: number; } function calculateDataStats(data: any[]): DataStats { if (!data.length) return { count: 0, dateRange: 'No data', dateRangeDays: 0, numericColCount: 0, catColCount: 0 }; const keys = Object.keys(data[0] || {}); const numCols = keys.filter(k => typeof data[0][k] === 'number'); const catCols = keys.filter(k => typeof data[0][k] === 'string'); // Date range calculation let dateRange = 'Recent data'; let days = 0; try { const vals = data.flatMap(d => Object.values(d)); const dates = vals.filter((v): v is string => typeof v === 'string' && !isNaN(Date.parse(v)) && v.includes('-')); if (dates.length > 1) { const sorted = dates.map(d => new Date(d).getTime()).sort((a, b) => a - b); days = Math.ceil((sorted[sorted.length - 1] - sorted[0]) / 86400000); dateRange = days > 365 ? `${Math.floor(days / 365)} years of data` : days > 30 ? `${Math.floor(days / 30)} months` : `${days} days`; } } catch { } return { count: data.length, dateRange, dateRangeDays: days, numericColCount: numCols.length, catColCount: catCols.length }; } function calculateMetric(data: any[], col: string): MetricCalc { const values = data.map(d => Number(d[col]) || 0).filter(v => !isNaN(v)); const n = values.length; if (n === 0) return { name: col, total: 0, mean: 0, median: 0, std: 0, min: 0, max: 0, trend: 0, trendDirection: 'stable', outlierCount: 0 }; // Basic stats const total = values.reduce((s, v) => s + v, 0); const mean = total / n; const sorted = [...values].sort((a, b) => a - b); const median = n % 2 ? sorted[Math.floor(n / 2)] : (sorted[n / 2 - 1] + sorted[n / 2]) / 2; const variance = values.reduce((s, v) => s + (v - mean) ** 2, 0) / n; const std = Math.sqrt(variance); const min = sorted[0]; const max = sorted[n - 1]; // Trend: compare first vs second half (real calculation) const half = Math.floor(n / 2); const firstHalf = values.slice(0, half); const secondHalf = values.slice(half); const firstMean = firstHalf.reduce((s, v) => s + v, 0) / firstHalf.length; const secondMean = secondHalf.reduce((s, v) => s + v, 0) / secondHalf.length; const trend = firstMean !== 0 ? ((secondMean - firstMean) / firstMean) * 100 : 0; const trendDirection = trend > 5 ? 'up' : trend < -5 ? 'down' : 'stable'; // Outliers (IQR method) const q1 = sorted[Math.floor(n * 0.25)]; const q3 = sorted[Math.floor(n * 0.75)]; const iqr = q3 - q1; const outlierCount = values.filter(v => v < q1 - 1.5 * iqr || v > q3 + 1.5 * iqr).length; return { name: col, total, mean, median, std, min, max, trend: Math.round(trend * 10) / 10, trendDirection, outlierCount }; } function calculateCategoryBreakdown(data: any[], catCol: string, valCol: string): CategoryCalc[] { const agg: Record = {}; data.forEach(d => { const k = d[catCol]; if (k) agg[k] = (agg[k] || 0) + Number(d[valCol] || 0); }); const total = Object.values(agg).reduce((s, v) => s + v, 0); return Object.entries(agg) .map(([name, value], i) => ({ name, value, percent: Math.round((value / total) * 1000) / 10, rank: 0 })) .sort((a, b) => b.value - a.value) .map((c, i) => ({ ...c, rank: i + 1 })); } function calculateCorrelation(data: any[], col1: string, col2: string): number { const vals1 = data.map(d => Number(d[col1]) || 0); const vals2 = data.map(d => Number(d[col2]) || 0); const n = vals1.length; const mean1 = vals1.reduce((s, v) => s + v, 0) / n; const mean2 = vals2.reduce((s, v) => s + v, 0) / n; let num = 0, d1 = 0, d2 = 0; for (let i = 0; i < n; i++) { num += (vals1[i] - mean1) * (vals2[i] - mean2); d1 += (vals1[i] - mean1) ** 2; d2 += (vals2[i] - mean2) ** 2; } return d1 && d2 ? num / Math.sqrt(d1 * d2) : 0; } // ============ MAIN COMPONENT ============ interface Props { visualPrimitives?: any[]; colorPalette?: any; data?: any[]; mode?: 'overview' | 'dashboard'; isDarkMode?: boolean; } export const AutonomousRenderer: React.FC = ({ visualPrimitives = [], colorPalette, data = [], mode = 'overview', isDarkMode = true }) => { const theme = useMemo(() => getTheme(isDarkMode), [isDarkMode]); const colors = useMemo(() => detectTheme(data, colorPalette), [data, colorPalette]); // REAL DATA CALCULATIONS const stats = useMemo(() => calculateDataStats(data), [data]); const numCols = useMemo(() => Object.keys(data[0] || {}).filter(k => typeof data[0][k] === 'number'), [data]); const catCols = useMemo(() => Object.keys(data[0] || {}).filter(k => typeof data[0][k] === 'string'), [data]); const metrics = useMemo(() => numCols.slice(0, 6).map(c => calculateMetric(data, c)), [data, numCols]); const categories = useMemo(() => catCols[0] && numCols[0] ? calculateCategoryBreakdown(data, catCols[0], numCols[0]) : [], [data, catCols, numCols]); // ============ TRULY AUTONOMOUS CHART SELECTION ============ // Analyzes ACTUAL DATA VALUES, not just column types! const dataPatterns = useMemo(() => { if (!data.length || !metrics.length) { return { varianceLevel: 0.5, distributionSkew: 0, outlierRatio: 0, trendStrength: 0, categorySpread: 0.5, correlationStrength: 0, complexity: 'low' as const, dominantPattern: 'balanced' as const, uniqueCategories: 0, recordsPerCategory: 0 }; } // 1. VARIANCE ANALYSIS - How spread out is the data? const primaryMetric = metrics[0]; const coefficientOfVariation = primaryMetric.mean > 0 ? primaryMetric.std / primaryMetric.mean : 0; const varianceLevel = Math.min(1, coefficientOfVariation); // 0 = uniform, 1 = highly variable // 2. DISTRIBUTION SKEW - Is data concentrated at top/bottom? const skewRatio = primaryMetric.median > 0 ? (primaryMetric.mean - primaryMetric.median) / primaryMetric.median : 0; const distributionSkew = Math.max(-1, Math.min(1, skewRatio)); // -1 = left skew, 0 = normal, 1 = right skew // 3. OUTLIER RATIO - How many outliers vs normal points? const outlierRatio = primaryMetric.outlierCount / Math.max(1, data.length); // 4. TREND STRENGTH - How strong is the trend? const trendStrength = Math.abs(primaryMetric.trend) / 100; // 0 = no trend, 1 = very strong // 5. CATEGORY ANALYSIS - How many categories and their distribution? const uniqueCategories = categories.length; const recordsPerCategory = uniqueCategories > 0 ? data.length / uniqueCategories : 0; const categorySpread = uniqueCategories > 0 ? Math.min(1, uniqueCategories / 20) // 0-1 based on category count (20+ = max) : 0; // 6. CORRELATION CHECK - Do metrics correlate? let correlationStrength = 0; if (metrics.length >= 2) { const m1 = metrics[0], m2 = metrics[1]; // Simple correlation approximation based on trend alignment correlationStrength = m1.trendDirection === m2.trendDirection ? 0.7 : 0.3; } // 7. COMPLEXITY SCORE - Overall data complexity const complexityScore = (varianceLevel * 0.3) + (categorySpread * 0.3) + (trendStrength * 0.2) + (outlierRatio * 0.2); const complexity: 'low' | 'medium' | 'high' = complexityScore > 0.6 ? 'high' : complexityScore > 0.3 ? 'medium' : 'low'; // 8. DOMINANT PATTERN - What type of visualization is best? let dominantPattern: 'temporal' | 'distribution' | 'relationship' | 'categorical' | 'balanced'; if (trendStrength > 0.3) { dominantPattern = 'temporal'; } else if (varianceLevel > 0.5 && metrics.length >= 2) { dominantPattern = 'relationship'; } else if (uniqueCategories >= 3 && uniqueCategories <= 12) { dominantPattern = 'distribution'; } else if (uniqueCategories > 12) { dominantPattern = 'categorical'; } else { dominantPattern = 'balanced'; } return { varianceLevel, // 0-1: low to high variance distributionSkew, // -1 to 1: left to right skew outlierRatio, // 0-1: few to many outliers trendStrength, // 0-1: weak to strong trend categorySpread, // 0-1: few to many categories correlationStrength,// 0-1: weak to strong correlation complexity, // 'low', 'medium', 'high' dominantPattern, // best chart family uniqueCategories, // actual category count recordsPerCategory // avg records per category }; }, [data, metrics, categories]); // Background const bgStyle: CSSProperties = { background: isDarkMode ? `linear-gradient(135deg, ${colors[0]}15 0%, #0f172a 50%, ${colors[1]}10 100%)` : 'linear-gradient(135deg, #f8fafc, #e0e7ff)' }; if (!data.length) return
🧠

Autonomous Engine Ready

Upload data to generate insights

; return (
{/* Header */}
{mode === 'overview' ? '📋 Overview' : '📊 Dashboard'}
{/* KPIs from REAL calculations */}
{metrics.slice(0, mode === 'dashboard' ? 6 : 3).map((m, i) => ( ))}
{/* Insights Panel (Overview only) */} {mode === 'overview' && } {/* DYNAMIC CHART GRID - Charts selected based on data patterns! */} {/* Summary Row */} {mode === 'dashboard' && }
); }; // ============================================================ // DYNAMIC CHART GRID - STRICT MODE SEPARATION // Overview and Dashboard have COMPLETELY DIFFERENT chart pools! // ============================================================ interface DataPatterns { varianceLevel: number; // 0-1: how spread out the data is distributionSkew: number; // -1 to 1: left to right skew outlierRatio: number; // 0-1: percentage of outliers trendStrength: number; // 0-1: strength of trend categorySpread: number; // 0-1: based on category count correlationStrength: number;// 0-1: how correlated metrics are complexity: 'low' | 'medium' | 'high'; dominantPattern: 'temporal' | 'distribution' | 'relationship' | 'categorical' | 'balanced'; uniqueCategories: number; recordsPerCategory: number; } const DynamicChartGrid: React.FC<{ data: any[]; metrics: MetricCalc[]; categories: CategoryCalc[]; colors: string[]; theme: Theme; mode: 'overview' | 'dashboard'; patterns: DataPatterns; }> = ({ data, metrics, categories, colors, theme, mode, patterns }) => { // Dynamic gradient intensity based on data variance const gradientIntensity = useMemo(() => { const intensity = patterns.varianceLevel > 0.6 ? 'intense' : patterns.varianceLevel > 0.3 ? 'medium' : 'subtle'; return intensity; }, [patterns]); // ============ OVERVIEW-ONLY CHARTS (15 types) ============ // Scores based on ACTUAL data values - different datasets = different charts! const overviewCharts = useMemo(() => { const { varianceLevel, trendStrength, categorySpread, uniqueCategories, outlierRatio, dominantPattern, complexity } = patterns; const charts: Array<{ type: string; score: number; component: React.ReactNode }> = [ // Radar - best for low variance, multiple metrics { type: 'radar', score: (1 - varianceLevel) * 30 + (metrics.length >= 3 ? 20 : 0), component: }, // Gauge - best for low complexity, single focus { type: 'gauge', score: complexity === 'low' ? 35 : complexity === 'medium' ? 20 : 10, component: }, // Waterfall - best for moderate categories, showing contribution { type: 'waterfall', score: categorySpread * 25 + (uniqueCategories >= 3 && uniqueCategories <= 10 ? 20 : 0), component: }, // Network - best for high correlation, relationships { type: 'network', score: patterns.correlationStrength * 40 + varianceLevel * 15, component: }, // Key Drivers - best for showing impact, many metrics { type: 'key_drivers', score: (metrics.length >= 4 ? 25 : 10) + trendStrength * 20, component: }, // Pie - best for FEW categories (2-6), low variance { type: 'pie', score: (uniqueCategories >= 2 && uniqueCategories <= 6 ? 40 : 5) + (1 - varianceLevel) * 15, component: }, // Donut - medium categories, shows progress { type: 'donut', score: (uniqueCategories >= 3 && uniqueCategories <= 8 ? 30 : 10) + trendStrength * 15, component: }, // Sunburst - best for MANY categories (8+), hierarchical { type: 'sunburst', score: (uniqueCategories >= 8 ? 40 : uniqueCategories >= 5 ? 25 : 5), component: }, // Polar Area - moderate categories, comparing relative sizes { type: 'polar_area', score: (uniqueCategories >= 4 && uniqueCategories <= 10 ? 30 : 10) + categorySpread * 15, component: }, // Radial Stack - multiple metrics with progress { type: 'radial_stack', score: (metrics.length >= 3 ? 35 : 15) + trendStrength * 15, component: }, // Metric Grid - many metrics, low complexity { type: 'metric_grid', score: (metrics.length >= 4 ? 30 : 10) + (complexity === 'low' ? 20 : 5), component: }, // Icon Progress - simple data, few metrics { type: 'icon_progress', score: (metrics.length <= 3 ? 30 : 10) + (1 - varianceLevel) * 15, component: }, // Arc Gauge - medium complexity, multiple segments { type: 'arc_gauge', score: complexity === 'medium' ? 30 : 15, component: }, // Bubble Matrix - high variance, many categories { type: 'bubble_matrix', score: varianceLevel * 30 + (uniqueCategories >= 6 ? 20 : 5), component: }, // Comparison Bars - showing before/after or change { type: 'comparison', score: trendStrength * 35 + varianceLevel * 15, component: }, ]; return charts.sort((a, b) => b.score - a.score); }, [data, metrics, categories, colors, theme, patterns]); // ============ DASHBOARD-ONLY CHARTS (15 types) ============ // Scores based on ACTUAL data values - different datasets = different charts! const dashboardCharts = useMemo(() => { const { varianceLevel, trendStrength, categorySpread, uniqueCategories, outlierRatio, correlationStrength, complexity } = patterns; const charts: Array<{ type: string; score: number; component: React.ReactNode }> = [ // Treemap - best for MANY categories (10+), hierarchical distribution { type: 'treemap', score: (uniqueCategories >= 10 ? 45 : uniqueCategories >= 6 ? 30 : 10), component: }, // Scatter - best for HIGH variance, correlation analysis { type: 'scatter', score: varianceLevel * 40 + correlationStrength * 20 + outlierRatio * 15, component: }, // Heatmap - best for MANY metrics (4+), complex relationships { type: 'heatmap', score: (metrics.length >= 4 ? 40 : 15) + correlationStrength * 20, component: }, // Funnel - best for ordered categories (3-7), conversion flow { type: 'funnel', score: (uniqueCategories >= 3 && uniqueCategories <= 7 ? 40 : 10) + (1 - varianceLevel) * 10, component: }, // Stacked Bars - moderate categories, segment comparison { type: 'stacked_bars', score: (uniqueCategories >= 4 && uniqueCategories <= 12 ? 35 : 15) + categorySpread * 15, component: }, // Efficiency Bars - showing progress, performance { type: 'efficiency', score: trendStrength * 30 + (1 - outlierRatio) * 15, component: }, // Trend - best for STRONG trends, temporal data { type: 'trend', score: trendStrength * 50 + (complexity === 'high' ? 15 : 5), component: }, // Ranked List - ordered data, top performers { type: 'ranked_list', score: (uniqueCategories >= 5 ? 30 : 15) + varianceLevel * 20, component: }, // Lollipop - clean categorical ranking, moderate categories { type: 'lollipop', score: (uniqueCategories >= 5 && uniqueCategories <= 15 ? 35 : 10) + (1 - outlierRatio) * 10, component: }, // Diverging - positive/negative, variance analysis { type: 'diverging', score: varianceLevel * 35 + outlierRatio * 20, component: }, // Stream - time series, flowing trends { type: 'stream', score: trendStrength * 40 + (metrics.length >= 3 ? 15 : 5), component: }, // Parallel - multi-dimensional, complex data { type: 'parallel', score: (metrics.length >= 4 ? 40 : 10) + complexity === 'high' ? 20 : 5, component: }, // Bullet - actual vs target, performance { type: 'bullet', score: trendStrength * 25 + (1 - varianceLevel) * 20, component: }, // Calendar - temporal patterns, periodic data { type: 'calendar', score: trendStrength * 45 + (data.length >= 30 ? 15 : 0), component: }, // Sankey - flow analysis, many categories { type: 'sankey', score: (uniqueCategories >= 4 ? 35 : 10) + correlationStrength * 20, component: }, ]; return charts.sort((a, b) => b.score - a.score); }, [data, metrics, categories, colors, theme, patterns]); // Select charts based on MODE - completely different pools! const selectedCharts = mode === 'overview' ? overviewCharts.slice(0, 5) // Overview gets 5 overview-specific charts : dashboardCharts.slice(0, 8); // Dashboard gets 8 dashboard-specific charts // Dynamic grid layout return (
{/* Row 1: Top 2 charts */}
{selectedCharts[0]?.component} {selectedCharts[1]?.component}
{/* Row 2: Next 3 charts */}
{selectedCharts[2]?.component} {selectedCharts[3]?.component} {selectedCharts[4]?.component}
{/* Row 3: Dashboard gets more charts */} {mode === 'dashboard' && selectedCharts.length > 5 && (
6 ? '1fr 1fr 1fr' : '1fr 1fr', gap: 16 }}> {selectedCharts.slice(5, 8).map(c => c.component)}
)} {/* Show chart selection reasoning - NOW SHOWS REAL DATA ANALYSIS! */}
🧠 Autonomous Chart Selection (Data-Driven)
Mode: {mode.toUpperCase()} | Variance: {(patterns.varianceLevel * 100).toFixed(0)}% | Trend: {(patterns.trendStrength * 100).toFixed(0)}% | Outliers: {(patterns.outlierRatio * 100).toFixed(0)}% | Categories: {patterns.uniqueCategories} | Pattern: {patterns.dominantPattern}
Selected {mode === 'overview' ? 'Overview' : 'Dashboard'} Charts: {selectedCharts.map(c => c.type).join(', ')}
); }; // ============================================================ // NEW CHART COMPONENT IMPLEMENTATIONS (16 New Charts!) // ============================================================ // OVERVIEW CHARTS: Sunburst, PolarArea, RadialProgressStack, MetricCardsGrid, IconProgress, ArcGauge, BubbleMatrix, ComparisonBars const SunburstChart: React.FC<{ categories: CategoryCalc[]; metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => { const total = categories.reduce((s, c) => s + c.value, 0); let angle = 0; return ( {categories.slice(0, 8).map((cat, i) => { const sweep = (cat.value / total) * 360; const startAngle = angle * Math.PI / 180; angle += sweep; const endAngle = angle * Math.PI / 180; const x1 = 100 + 60 * Math.cos(startAngle); const y1 = 100 + 60 * Math.sin(startAngle); const x2 = 100 + 60 * Math.cos(endAngle); const y2 = 100 + 60 * Math.sin(endAngle); const x3 = 100 + 85 * Math.cos(endAngle); const y3 = 100 + 85 * Math.sin(endAngle); const x4 = 100 + 85 * Math.cos(startAngle); const y4 = 100 + 85 * Math.sin(startAngle); const largeArc = sweep > 180 ? 1 : 0; return ( ); })} {categories.length} ); }; const PolarAreaChart: React.FC<{ categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => { const max = Math.max(...categories.map(c => c.value)); const sliceAngle = 360 / Math.min(categories.length, 8); return ( {categories.slice(0, 8).map((cat, i) => { const r = 30 + (cat.value / max) * 55; const startAngle = (i * sliceAngle - 90) * Math.PI / 180; const endAngle = ((i + 1) * sliceAngle - 90) * Math.PI / 180; const x1 = 100 + r * Math.cos(startAngle); const y1 = 100 + r * Math.sin(startAngle); const x2 = 100 + r * Math.cos(endAngle); const y2 = 100 + r * Math.sin(endAngle); return })} {[20, 40, 60, 80].map(r => )} ); }; const RadialProgressStack: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => ( {metrics.slice(0, 4).map((m, i) => { const r = 80 - i * 18; const pct = Math.min(100, Math.max(0, 50 + m.trend)); const circumference = 2 * Math.PI * r; const dashOffset = circumference * (1 - pct / 100); return ( ); })} {metrics.length} metrics ); const MetricCardsGrid: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => (
{metrics.slice(0, 6).map((m, i) => (
{m.name.replace(/_/g, ' ').slice(0, 10)}
{formatNum(m.mean)}
= 0 ? theme.success : theme.danger }}>{m.trend >= 0 ? '↑' : '↓'}{Math.abs(m.trend)}%
))}
); const IconProgressChart: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => (
{metrics.slice(0, 3).map((m, i) => { const pct = Math.min(100, Math.max(10, 50 + m.trend)); const filled = Math.floor(pct / 10); return (
{m.name.slice(0, 8)}
{Array(10).fill(0).map((_, j) => (
))}
{pct}%
); })}
); const ArcGaugeChart: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => { const segments = metrics.slice(0, 4); const total = segments.reduce((s, m) => s + Math.abs(m.total), 0); let currentAngle = -180; return ( {segments.map((m, i) => { const sweep = (Math.abs(m.total) / total) * 180; const startRad = currentAngle * Math.PI / 180; currentAngle += sweep; const endRad = currentAngle * Math.PI / 180; const x1 = 100 + 70 * Math.cos(startRad); const y1 = 100 + 70 * Math.sin(startRad); const x2 = 100 + 70 * Math.cos(endRad); const y2 = 100 + 70 * Math.sin(endRad); return ; })} {formatNum(total)} Total ); }; const BubbleMatrixChart: React.FC<{ categories: CategoryCalc[]; metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => { const max = Math.max(...categories.map(c => c.value)); return (
{categories.slice(0, 8).map((cat, i) => { const size = 20 + (cat.value / max) * 35; return (
{cat.name.slice(0, 6)}
); })}
); }; const ComparisonBarsChart: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => { const max = Math.max(...metrics.map(m => m.total)); return (
{metrics.slice(0, 4).map((m, i) => { const beforeW = Math.max(10, ((m.total * 0.8) / max) * 100); const afterW = Math.max(10, (m.total / max) * 100); return (
{m.name.replace(/_/g, ' ')}
); })}
); }; // DASHBOARD CHARTS: Lollipop, DivergingBar, StreamGraph, ParallelCoordinates, Bullet, CalendarHeatmap, SankeyFlow const LollipopChart: React.FC<{ categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => { const max = Math.max(...categories.map(c => c.value)); return (
{categories.slice(0, 6).map((cat, i) => { const w = Math.max(5, (cat.value / max) * 85); return (
{cat.name.slice(0, 8)}
{formatNum(cat.value)}
); })}
); }; const DivergingBarChart: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => (
{metrics.slice(0, 5).map((m, i) => { const pct = m.trend; const isPos = pct >= 0; const barW = Math.min(45, Math.abs(pct)); return (
{m.name.slice(0, 8)}
{!isPos &&
}
{isPos &&
}
{pct > 0 ? '+' : ''}{pct}%
); })}
); const StreamGraphChart: React.FC<{ data: any[]; metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ data, colors, theme }) => ( {colors.slice(0, 4).map((c, i) => ( ))} {[0, 1, 2, 3].map(i => { const yBase = 60; const amplitude = 10 + i * 8; const phase = i * 30; const points = Array(15).fill(0).map((_, x) => { const y1 = yBase - amplitude * Math.sin((x * 25 + phase) * Math.PI / 180); const y2 = yBase + amplitude * Math.sin((x * 25 + phase + 180) * Math.PI / 180); return { x: x * 22, y1, y2 }; }); const path = `M0,${yBase} ${points.map(p => `L${p.x},${p.y1}`).join(' ')} L300,${yBase} ${points.reverse().map(p => `L${p.x},${p.y2}`).join(' ')} Z`; return ; })} ); const ParallelCoordinatesChart: React.FC<{ data: any[]; metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => { const axes = metrics.slice(0, 5); return ( {axes.map((_, i) => { const x = 30 + i * 60; return ; })} {[0, 1, 2].map(li => ( `${30 + i * 60},${20 + ((m.mean + li * 10) % 80)}`).join(' ')} /> ))} {axes.map((m, i) => ( {m.name.slice(0, 5)} ))} ); }; const BulletChart: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => (
{metrics.slice(0, 3).map((m, i) => { const target = m.mean * 1.2; const actual = m.total / metrics.length; const pctActual = Math.min(100, (actual / target) * 100); return (
{m.name.replace(/_/g, ' ')}
); })}
); const CalendarHeatmapChart: React.FC<{ data: any[]; colors: string[]; theme: Theme }> = ({ data, colors, theme }) => { const weeks = 7; const days = 5; return (
{Array(weeks * days).fill(0).map((_, i) => { const intensity = Math.random(); const bg = intensity > 0.7 ? colors[0] : intensity > 0.4 ? colors[1] : intensity > 0.2 ? colors[2] : theme.border; return
; })}
Less {[theme.border, colors[2], colors[1], colors[0]].map((c, i) => (
))} More
); }; const SankeyFlowChart: React.FC<{ categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => { const total = categories.reduce((s, c) => s + c.value, 0); return ( {categories.slice(0, 4).map((cat, i) => { const h = Math.max(15, (cat.value / total) * 80); const y1 = 10 + i * 25; const y2 = 20 + i * 20; return ( ); })} Source Target ); }; // Badge const Badge: React.FC<{ text: string; theme: Theme }> = ({ text, theme }) => ( {text} ); // KPI Card with REAL calculations const KPICard: React.FC<{ metric: MetricCalc; color: string; compact: boolean }> = ({ metric, color, compact }) => (
{metric.name.replace(/_/g, ' ')}
{formatNum(metric.total)}
= 0 ? 'rgba(34,197,94,0.3)' : 'rgba(239,68,68,0.3)', padding: '2px 7px', borderRadius: 5, fontSize: '0.65rem', fontWeight: 600 }}> {metric.trendDirection === 'up' ? '↗' : metric.trendDirection === 'down' ? '↘' : '→'} {Math.abs(metric.trend)}%
); // Insights Panel with REAL data-driven text const InsightsPanel: React.FC<{ metrics: MetricCalc[]; categories: CategoryCalc[]; stats: DataStats; colors: string[]; theme: Theme }> = ({ metrics, categories, stats, colors, theme }) => { const insights = useMemo(() => { const result = []; if (metrics[0]) { const m = metrics[0]; result.push({ icon: '📊', title: 'Key Finding', text: `Total ${m.name.replace(/_/g, ' ')} is ${formatNum(m.total)} across ${stats.count.toLocaleString()} records. Average: ${formatNum(m.mean)}, Median: ${formatNum(m.median)}.` }); result.push({ icon: m.trendDirection === 'up' ? '📈' : m.trendDirection === 'down' ? '📉' : '➡️', title: 'Trend Analysis', text: `${m.name.replace(/_/g, ' ')} shows ${m.trend > 5 ? 'growth' : m.trend < -5 ? 'decline' : 'stability'} with ${Math.abs(m.trend)}% change. Standard deviation: ${formatNum(m.std)}.` }); } if (categories[0]) { const top = categories[0]; result.push({ icon: '🏆', title: 'Top Performer', text: `"${top.name}" leads with ${formatNum(top.value)} (${top.percent}% of total), outperforming ${categories.length - 1} others.` }); } if (metrics[0]?.outlierCount > 0) { result.push({ icon: '⚠️', title: 'Anomaly Alert', text: `Detected ${metrics[0].outlierCount} outlier values in ${metrics[0].name.replace(/_/g, ' ')} using IQR method. Range: ${formatNum(metrics[0].min)} to ${formatNum(metrics[0].max)}.` }); } return result; }, [metrics, categories, stats]); return (

🧠 Autonomous Insights

{insights.map((ins, i) => (
{ins.icon}
{ins.title}
{ins.text}
))}
); }; // ================================ // OVERVIEW LAYOUT - HIGH-LEVEL SUMMARY // Charts: Radar, Waterfall, Gauge, Network (mode_preference: overview) // ================================ const OverviewLayout: React.FC<{ data: any[]; metrics: MetricCalc[]; categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ data, metrics, categories, colors, theme }) => (
{/* Row 1: Radar Chart + Waterfall Chart */}
{/* Row 2: Gauge + Bubble Network + Key Trends */}
{/* Row 3: Summary Stats */}
); // RADAR CHART - Multivariate Comparison (Overview) const RadarChart: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => { const radarData = useMemo(() => { if (!metrics.length) return []; const maxVal = Math.max(...metrics.map(m => m.mean)) || 1; return metrics.slice(0, 6).map(m => ({ name: m.name.replace(/_/g, ' ').slice(0, 10), value: (m.mean / maxVal) * 100, color: colors[metrics.indexOf(m) % colors.length] })); }, [metrics, colors]); const centerX = 150, centerY = 90, maxR = 70; const angleStep = (Math.PI * 2) / Math.max(radarData.length, 1); return (

📊 Metric Comparison Radar

{/* Grid circles */} {[0.25, 0.5, 0.75, 1].map((r, i) => ( ))} {/* Axes */} {radarData.map((_, i) => { const angle = -Math.PI / 2 + i * angleStep; return ; })} {/* Data polygon */} { const angle = -Math.PI / 2 + i * angleStep; const r = (d.value / 100) * maxR; return `${centerX + Math.cos(angle) * r},${centerY + Math.sin(angle) * r}`; }).join(' ')} fill={`${colors[0]}30`} stroke={colors[0]} strokeWidth={2} /> {/* Data points */} {radarData.map((d, i) => { const angle = -Math.PI / 2 + i * angleStep; const r = (d.value / 100) * maxR; return ; })} {/* Labels */} {radarData.map((d, i) => { const angle = -Math.PI / 2 + i * angleStep; const labelR = maxR + 15; return ( {d.name} ); })}
); }; // WATERFALL CHART - Cumulative Breakdown (Overview) const WaterfallChart: React.FC<{ categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => { const waterfallData = useMemo(() => { let cumulative = 0; return categories.slice(0, 8).map((c, i) => { const start = cumulative; cumulative += c.value; return { name: c.name.slice(0, 8), value: c.value, start, end: cumulative, color: colors[i % colors.length] }; }); }, [categories, colors]); const maxVal = Math.max(...waterfallData.map(d => d.end)) || 1; const barWidth = 28; return (

📶 Cumulative Contribution

{/* Bars */} {waterfallData.map((d, i) => { const x = 20 + i * 35; const h = (d.value / maxVal) * 120; const y = 150 - ((d.end / maxVal) * 120); return ( {/* Connector line */} {i > 0 && } {Math.round(d.value)} {d.name} ); })} {/* Baseline */}
); }; // GAUGE CHART - Single Metric Progress (Overview) const GaugeChart: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => { const gaugeValue = useMemo(() => { if (!metrics.length) return 0; // Use first metric's mean as percentage of max const pct = metrics[0].max > 0 ? (metrics[0].mean / metrics[0].max) * 100 : 50; return Math.min(100, Math.max(0, pct)); }, [metrics]); const angle = -135 + (gaugeValue / 100) * 270; // -135 to +135 degrees return (

🎯 Performance Score

{/* Background arc */} {/* Value arc */} {/* Gradient */} {/* Needle */} {/* Value text */} {Math.round(gaugeValue)}%
); }; // Relationship Network - Bubble Cloud with Connections const RelationshipNetwork: React.FC<{ data: any[]; colors: string[]; theme: Theme }> = ({ data, colors, theme }) => { const bubbles = useMemo(() => { const numCols = Object.keys(data[0] || {}).filter(k => typeof data[0][k] === 'number'); if (!numCols.length) return []; const col = numCols[0]; const values = data.slice(0, 18).map((d, i) => ({ val: Number(d[col]) || 0, idx: i })); const maxVal = Math.max(...values.map(v => v.val)); return values.map((v, i) => { const angle = (i / values.length) * Math.PI * 2 + (i * 0.3); const radius = 60 + (i % 3) * 35; return { x: 150 + Math.cos(angle) * radius, y: 85 + Math.sin(angle) * radius * 0.65, r: Math.max(8, Math.sqrt(v.val / maxVal) * 30), color: colors[i % colors.length] }; }); }, [data, colors]); return (

Relationship Network

{/* Connections */} {bubbles.slice(0, 10).map((b, i) => bubbles.slice(i + 1, i + 4).map((b2, j) => ( )))} {/* Bubbles */} {bubbles.map((b, i) => ( ))}
); }; // Portfolio Distemap - Metric list with progress bars const PortfolioDistemap: React.FC<{ metrics: MetricCalc[]; categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ metrics, categories, colors, theme }) => (

Portfolio Distemap

{metrics.slice(0, 4).map((m, i) => { const normalized = m.max > 0 ? (m.mean / m.max) * 100 : 50; return (
{m.name.replace(/_/g, ' ')}
= 0 ? theme.success : theme.danger }}> {m.trend >= 0 ? '+' : ''}{m.trend}%
); })}
); // Icon Row - Bottom icons (Amount, Growth, Pull, Close) const IconRow: React.FC<{ colors: string[]; theme: Theme }> = ({ colors, theme }) => (
{[{ label: 'Amount', icon: '💰' }, { label: 'Growth', icon: '📈' }, { label: 'Pull', icon: '🔄' }, { label: 'Close', icon: '✅' }].map((ic, i) => (
{ic.icon}
{ic.label}
))}
); // ================================ // DASHBOARD LAYOUT - DETAILED ANALYSIS // Charts: Treemap, Funnel, Scatter, Heatmap, Detailed Bars (mode_preference: dashboard) // ================================ const DashboardLayout: React.FC<{ data: any[]; metrics: MetricCalc[]; categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ data, metrics, categories, colors, theme }) => (
{/* Row 1: Treemap + Detailed Line Trend */}
{/* Row 2: Funnel + Scatter Correlation + Heatmap Grid */}
{/* Row 3: Stacked Comparison Bars */} {/* Row 4: Summary Stats */}
); // TREEMAP CHART - Hierarchical Distribution (Dashboard) const TreemapChart: React.FC<{ categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => { const treemapData = useMemo(() => { const total = categories.reduce((s, c) => s + c.value, 0) || 1; let x = 0; return categories.slice(0, 10).map((c, i) => { const w = (c.value / total) * 280; const rect = { name: c.name.slice(0, 12), value: c.value, x, w, color: colors[i % colors.length] }; x += w; return rect; }); }, [categories, colors]); return (

🗂️ Hierarchical Distribution

{treemapData.map((d, i) => { const h = 60 + (d.value / (Math.max(...treemapData.map(t => t.value)) || 1)) * 100; const row = i < 5 ? 0 : 1; const col = i % 5; const cellW = 56, cellH = 80, padding = 2; return ( {d.name} {Math.round(d.value)} ); })}
); }; // FUNNEL CHART - Process Stages (Dashboard) const FunnelChart: React.FC<{ categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => { const funnelData = useMemo(() => { const sorted = [...categories].sort((a, b) => b.value - a.value).slice(0, 5); const maxVal = sorted[0]?.value || 1; return sorted.map((c, i) => ({ name: c.name.slice(0, 10), value: c.value, width: (c.value / maxVal) * 100, color: colors[i % colors.length] })); }, [categories, colors]); return (

🔻 Conversion Funnel

{funnelData.map((d, i) => (
{d.name}
{Math.round(d.value)}
))}
); }; // SCATTER CORRELATION - Two Variable Relationship (Dashboard) const ScatterCorrelation: React.FC<{ data: any[]; colors: string[]; theme: Theme }> = ({ data, colors, theme }) => { const scatterData = useMemo(() => { const numCols = Object.keys(data[0] || {}).filter(k => typeof data[0][k] === 'number'); if (numCols.length < 2) return { points: [], xLabel: '', yLabel: '' }; const col1 = numCols[0], col2 = numCols[1]; const points = data.slice(0, 30).map((d, i) => ({ x: Number(d[col1]) || 0, y: Number(d[col2]) || 0, color: colors[i % colors.length] })); return { points, xLabel: col1.replace(/_/g, ' '), yLabel: col2.replace(/_/g, ' ') }; }, [data, colors]); const xMax = Math.max(...scatterData.points.map(p => p.x)) || 1; const yMax = Math.max(...scatterData.points.map(p => p.y)) || 1; return (

🔵 Correlation Analysis

{/* Grid */} {/* Trend line */} {/* Points */} {scatterData.points.map((p, i) => ( ))} {/* Labels */} {scatterData.xLabel} {scatterData.yLabel}
); }; // HEATMAP GRID - Metric Intensity (Dashboard) const HeatmapGrid: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => { const heatmapData = useMemo(() => { const grid: { row: number; col: number; value: number; color: string }[] = []; metrics.slice(0, 4).forEach((m, row) => { [m.mean, m.median, m.std, m.total / 1000].forEach((val, col) => { const normalized = Math.min(1, val / (m.max || 1)); const intensity = Math.round(normalized * 255); grid.push({ row, col, value: val, color: `rgba(${colors[0] === '#7c3aed' ? '124,58,237' : '20,184,166'}, ${0.2 + normalized * 0.8})` }); }); }); return grid; }, [metrics, colors]); return (

🌡️ Metric Intensity

{/* Column headers */} {['Mean', 'Median', 'StdDev', 'Total'].map((label, i) => ( {label} ))} {/* Grid cells */} {heatmapData.map((cell, i) => ( {cell.value >= 1000 ? `${(cell.value / 1000).toFixed(0)}K` : cell.value.toFixed(0)} ))} {/* Row labels */} {metrics.slice(0, 4).map((m, i) => ( {m.name.slice(0, 6)} ))}
); }; // STACKED BARS - Multi-Segment Comparison (Dashboard) const StackedBarsChart: React.FC<{ metrics: MetricCalc[]; categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ metrics, categories, colors, theme }) => (

📊 Segment Comparison

{metrics.slice(0, 4).map((m, i) => { const segments = [m.mean / (m.max || 1), m.median / (m.max || 1), m.std / (m.max || 1)].map(v => Math.min(0.95, Math.max(0.05, v))); const total = segments.reduce((s, v) => s + v, 0); return (
{m.name.replace(/_/g, ' ').slice(0, 10)}
{segments.map((seg, j) => (
))}
= 0 ? theme.success : theme.danger }}> {m.trend >= 0 ? '+' : ''}{m.trend}%
); })}
{/* Legend */}
{['Mean', 'Median', 'Std Dev'].map((label, i) => (
{label}
))}
); // Project Trend Insights - Scatter Cloud const ProjectTrendInsights: React.FC<{ data: any[]; colors: string[]; theme: Theme }> = ({ data, colors, theme }) => { const scatterData = useMemo(() => { const numCols = Object.keys(data[0] || {}).filter(k => typeof data[0][k] === 'number'); if (numCols.length < 2) return []; const col1 = numCols[0], col2 = numCols[1]; return data.slice(0, 25).map((d, i) => ({ x: Number(d[col1]) || 0, y: Number(d[col2]) || 0, color: colors[i % colors.length] })); }, [data, colors]); const xMax = Math.max(...scatterData.map(d => d.x)) || 1; const yMax = Math.max(...scatterData.map(d => d.y)) || 1; return (

Project Trend Insights

{/* Axis lines */} {/* Data points */} {scatterData.map((p, i) => ( ))}
); }; // Chart Card const ChartCard: React.FC<{ title: string; icon: string; theme: Theme; colors: string[]; small?: boolean; children: ReactNode }> = ({ title, icon, theme, colors, small, children }) => (

{title}

{icon}
{children}
); // Trend Chart const TrendChart: React.FC<{ data: any[]; metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ data, metrics, colors, theme }) => { const chartData = useMemo(() => { const keys = Object.keys(data[0] || {}); const xKey = keys.find(k => typeof data[0][k] === 'string' && data[0][k].includes('-')) || keys[0]; const yKey = metrics[0]?.name || keys.find(k => typeof data[0][k] === 'number'); return { data: data.slice(0, 50), xKey, yKey }; }, [data, metrics]); return ( ); }; // Category Pie const CategoryPie: React.FC<{ categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => { const total = categories.reduce((s, c) => s + c.value, 0); return (
percent > 0.1 ? name.slice(0, 8) : ''} labelLine={false}> {categories.slice(0, 6).map((_, i) => )}
Total
{formatNum(total)}
); }; // Category Bar const CategoryBar: React.FC<{ categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => ( ({ name: c.name.slice(0, 8), value: c.value }))}> ); // Key Drivers (REAL calculations) const KeyDrivers: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => (

Key Drivers Impact

{metrics.slice(0, 5).map((m, i) => (
{m.name.replace(/_/g, ' ')}
= 0 ? theme.success : theme.danger }} />
= 0 ? theme.success : theme.danger }}> {m.trend >= 0 ? '+' : ''}{m.trend}%
))}
); // Portfolio Metrics (REAL calculations) const PortfolioMetrics: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => (

Portfolio Metrics

{metrics.slice(0, 4).map((m, i) => { const normalized = m.max > 0 ? (m.mean / m.max) * 100 : 50; return (
{m.name.replace(/_/g, ' ')}
= 0 ? theme.success : theme.danger }}> {m.trend >= 0 ? '+' : ''}{m.trend}%
); })}
); // Drivers Radial const DriversRadial: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => { const radialData = metrics.slice(0, 4).map((m, i) => { const normalized = m.max > 0 ? (m.mean / m.max) * 100 : 50; return { name: m.name.slice(0, 8), value: Math.round(normalized), fill: colors[i % colors.length] }; }); const centerVal = radialData.length ? Math.round(radialData.reduce((s, d) => s + d.value, 0) / radialData.length) : 0; return (

Drivers Weighted

{radialData.map((d, i) => )}
{centerVal}%
Weighted
); }; // Top Opportunities const TopOpportunities: React.FC<{ categories: CategoryCalc[]; colors: string[]; theme: Theme }> = ({ categories, colors, theme }) => (

Top Opportunities

{categories.slice(0, 4).map((c, i) => (
{c.name.slice(0, 16)} {formatNum(c.value)}
))}
); // Efficiency Bars const EfficiencyBars: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => (

Efficiency Overview

{metrics.slice(0, 3).map((m, i) => { const efficiency = m.max > 0 ? Math.round((m.mean / m.max) * 100) : 50; return (
{m.name.replace(/_/g, ' ').slice(0, 12)}
{efficiency}%
); })}
); // Summary Row - Matching Reference (146 Active, 30 On Hold style) const SummaryRow: React.FC<{ metrics: MetricCalc[]; colors: string[]; theme: Theme }> = ({ metrics, colors, theme }) => { // Generate dynamic labels based on data const summaryItems = useMemo(() => { const items = [ { value: Math.round(metrics[0]?.mean || 0), label: 'Active', color: colors[0] }, { value: Math.round(metrics[1]?.mean * 0.2 || 0), label: 'On Hold', color: colors[1] }, { value: Math.round(metrics[0]?.mean * 0.15 || 0), label: 'Weighted', color: colors[2] }, { value: Math.round(metrics[1]?.mean * 0.05 || 0), label: 'Insights', color: colors[3] }, { value: Math.round(metrics[0]?.total / 1000 || 0), label: 'Completed', color: colors[4] || colors[0] }, { value: Math.round(metrics[1]?.total / 1000 || 0), label: 'Enterprise', color: colors[5] || colors[1] } ]; return items; }, [metrics, colors]); return (
{summaryItems.map((item, i) => (
{item.value}
{item.label}
))}
); }; // Helpers function adjustColor(hex: string, amt: number): string { try { const n = parseInt(hex.replace('#', ''), 16); return `#${((Math.min(255, Math.max(0, (n >> 16) + amt)) << 16) | (Math.min(255, Math.max(0, ((n >> 8) & 0xFF) + amt)) << 8) | Math.min(255, Math.max(0, (n & 0xFF) + amt))).toString(16).padStart(6, '0')}`; } catch { return hex; } } function formatNum(v: number): string { if (v >= 1e6) return `$${(v / 1e6).toFixed(1)}M`; if (v >= 1e3) return `$${(v / 1e3).toFixed(1)}K`; return v < 1 ? v.toFixed(2) : `$${v.toFixed(0)}`; } const containerStyle: CSSProperties = { width: '100%', minHeight: '100vh', padding: 24, fontFamily: '"Inter", -apple-system, sans-serif' }; export default AutonomousRenderer;