/** * GR TrackSense - Racing Telemetry Dashboard * * Theme: "Mission Control meets Motorsport" * Colors: Zinc blacks + GR Red (#FF4500) * Fonts: Chakra Petch (display), Exo 2 (body), JetBrains Mono (data) * * Features: * - Racing perspective 3D background * - Real-time telemetry simulation * - SVG arc gauges (RPM, Speed) * - Rolling line charts (throttle/brake) * - Track map with position dot * - AI console terminal */ import React, { useState, useEffect, useRef, useMemo } from 'react'; import { Canvas, useFrame } from '@react-three/fiber'; import { Stars } from '@react-three/drei'; import { motion, AnimatePresence } from 'framer-motion'; import { Gauge, Activity, Map, Trophy, Terminal, ChevronRight, Zap, Radio, Settings } from 'lucide-react'; import * as THREE from 'three'; // ============================================ // TYPES // ============================================ type ViewState = 'landing' | 'dashboard' | 'team' | 'docs'; interface TelemetryData { rpm: number; speed: number; gear: number; throttle: number; brake: number; steering: number; } interface LogEntry { id: string; timestamp: string; level: 'INFO' | 'WARN' | 'ALERT'; message: string; } // ============================================ // CONSTANTS // ============================================ const COLORS = { background: '#0a0a0a', surface: '#141414', accent: '#FF4500', accentDim: 'rgba(255, 69, 0, 0.2)', text: '#ffffff', textMuted: '#71717a', border: 'rgba(255, 255, 255, 0.1)', }; const BOOT_MESSAGES = [ 'INITIALIZING ECU PROTOCOLS...', 'SYNCING SATELLITE UPLINK...', 'LOADING TELEMETRY MODULES...', 'CALIBRATING SENSORS...', 'CONNECTING TO RACE CONTROL...', 'SYSTEM READY', ]; const AI_MESSAGES = [ { level: 'INFO', message: 'Tire temp optimal - 92°C' }, { level: 'WARN', message: 'Sector 2 Yellow Flag detected' }, { level: 'INFO', message: 'Fuel load: 42.3L remaining' }, { level: 'ALERT', message: 'DRS Zone approaching' }, { level: 'INFO', message: 'Gap to P1: -2.341s' }, { level: 'WARN', message: 'Brake temp elevated - 680°C' }, ]; // ============================================ // 3D RACING BACKGROUND // ============================================ const RacingTrack = () => { const meshRef = useRef(null); const particlesRef = useRef(null); // Road geometry const roadGeometry = useMemo(() => { const geometry = new THREE.PlaneGeometry(4, 100, 1, 50); const positions = geometry.attributes.position.array as Float32Array; // Add perspective curve for (let i = 0; i < positions.length; i += 3) { const z = positions[i + 2]; positions[i] *= 1 + z * 0.01; // Widen at distance } return geometry; }, []); // Speed particles const particles = useMemo(() => { const count = 200; const positions = new Float32Array(count * 3); for (let i = 0; i < count; i++) { positions[i * 3] = (Math.random() - 0.5) * 10; positions[i * 3 + 1] = Math.random() * 5; positions[i * 3 + 2] = Math.random() * -50; } return positions; }, []); useFrame((state) => { if (particlesRef.current) { const positions = particlesRef.current.geometry.attributes.position.array as Float32Array; for (let i = 0; i < positions.length; i += 3) { positions[i + 2] += 0.5; // Move toward camera if (positions[i + 2] > 5) { positions[i + 2] = -50; positions[i] = (Math.random() - 0.5) * 10; } } particlesRef.current.geometry.attributes.position.needsUpdate = true; } }); return ( <> {/* Road */} {/* Kerbs */} {/* Speed particles */} {/* Background stars */} ); }; // ============================================ // PRELOADER // ============================================ const Preloader: React.FC<{ onComplete: () => void }> = ({ onComplete }) => { const [progress, setProgress] = useState(0); const [currentLog, setCurrentLog] = useState(0); const [logs, setLogs] = useState([]); useEffect(() => { const progressInterval = setInterval(() => { setProgress(prev => { if (prev >= 100) { clearInterval(progressInterval); setTimeout(onComplete, 500); return 100; } return prev + 2; }); }, 50); const logInterval = setInterval(() => { setCurrentLog(prev => { if (prev < BOOT_MESSAGES.length - 1) { setLogs(l => [...l, BOOT_MESSAGES[prev]]); return prev + 1; } clearInterval(logInterval); return prev; }); }, 400); return () => { clearInterval(progressInterval); clearInterval(logInterval); }; }, [onComplete]); return ( {/* Grid background */}
{/* Scanning line */}
{/* Logo */}
{/* Console logs */}
{logs.map((log, i) => ( > {log} ))}
{/* Progress bar */}
{/* Progress text */}
INITIALIZING {progress}%
); }; // ============================================ // GAUGE COMPONENT // ============================================ const ArcGauge: React.FC<{ value: number; max: number; label: string; unit: string; color?: string; }> = ({ value, max, label, unit, color = '#FF4500' }) => { const percentage = (value / max) * 100; const circumference = 2 * Math.PI * 45; const strokeDashoffset = circumference - (percentage / 100) * circumference * 0.75; return (
{/* Background arc */} {/* Value arc */} {/* Center display */}
{Math.round(value)} {unit}
{/* Label */}
{label}
); }; // ============================================ // TERMINAL COMPONENT // ============================================ const AIConsole: React.FC = () => { const [logs, setLogs] = useState([]); const scrollRef = useRef(null); useEffect(() => { const interval = setInterval(() => { const randomMsg = AI_MESSAGES[Math.floor(Math.random() * AI_MESSAGES.length)]; const newLog: LogEntry = { id: Date.now().toString(), timestamp: new Date().toLocaleTimeString('en-US', { hour12: false }), level: randomMsg.level as LogEntry['level'], message: randomMsg.message, }; setLogs(prev => [...prev.slice(-20), newLog]); }, 2000); return () => clearInterval(interval); }, []); useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } }, [logs]); const levelColors = { INFO: 'text-blue-400', WARN: 'text-yellow-400', ALERT: 'text-[#FF4500]', }; return (
AI Race Engineer
{logs.map(log => (
{log.timestamp} [{log.level}] {log.message}
))}
); }; // ============================================ // TRACK MAP COMPONENT // ============================================ const TrackMap: React.FC = () => { const [position, setPosition] = useState(0); // Simplified Fuji Speedway path const trackPath = "M 50 20 Q 80 20 85 50 Q 90 80 70 90 Q 50 100 30 90 Q 10 80 15 50 Q 20 20 50 20"; useEffect(() => { const interval = setInterval(() => { setPosition(prev => (prev + 0.5) % 100); }, 50); return () => clearInterval(interval); }, []); return (
Fuji Speedway
{/* Track outline */} {/* Track surface */} {/* Position dot */} {/* Start/finish */}
); }; // ============================================ // DASHBOARD // ============================================ const Dashboard: React.FC = () => { const [telemetry, setTelemetry] = useState({ rpm: 6500, speed: 180, gear: 4, throttle: 75, brake: 0, steering: 5, }); // Simulate live telemetry useEffect(() => { const interval = setInterval(() => { setTelemetry(prev => ({ rpm: Math.max(3000, Math.min(9000, prev.rpm + (Math.random() - 0.5) * 500)), speed: Math.max(60, Math.min(300, prev.speed + (Math.random() - 0.5) * 20)), gear: Math.max(1, Math.min(8, prev.gear + (Math.random() > 0.9 ? (Math.random() > 0.5 ? 1 : -1) : 0))), throttle: Math.max(0, Math.min(100, prev.throttle + (Math.random() - 0.5) * 30)), brake: Math.max(0, Math.min(100, prev.brake + (Math.random() - 0.5) * 20)), steering: Math.max(-45, Math.min(45, prev.steering + (Math.random() - 0.5) * 10)), })); }, 100); return () => clearInterval(interval); }, []); return (
{/* Header */}

GR TRACKSENSE

TELEMETRY ACTIVE

LIVE
{/* Dashboard Grid */}
{/* Main Gauges */}
{telemetry.gear}
GEAR
{/* Throttle/Brake */}
Throttle
{Math.round(telemetry.throttle)}%
Brake
{Math.round(telemetry.brake)}%
{/* Track Map */}
{/* AI Console */}
{/* Leaderboard */}
Standings
{[ { pos: 1, driver: 'VER', gap: 'LEADER', tire: 'M' }, { pos: 2, driver: 'NOR', gap: '+2.341', tire: 'M' }, { pos: 3, driver: 'YOU', gap: '+4.892', tire: 'H' }, { pos: 4, driver: 'LEC', gap: '+6.104', tire: 'S' }, ].map(row => (
{row.pos} {row.driver} {row.gap} {row.tire}
))}
); }; // ============================================ // HERO / LANDING // ============================================ const Hero: React.FC<{ onEnter: () => void }> = ({ onEnter }) => { return (
{/* 3D Background */}
{/* Scanlines overlay */}
{/* Content */}
{/* Badge */}
GR Hackathon 2024
{/* Headline */}

MASTER
THE TRACK

{/* Subheadline */}

Real-time telemetry and predictive analytics for the next generation of motorsport.

{/* CTA */} Enter Dashboard
{/* Bottom stats */}
{[ { label: 'Data Points/Sec', value: '10,000+' }, { label: 'Latency', value: '<5ms' }, { label: 'Accuracy', value: '99.7%' }, ].map(stat => (
{stat.value}
{stat.label}
))}
); }; // ============================================ // MAIN APP // ============================================ export default function GRTrackSense() { const [loading, setLoading] = useState(true); const [view, setView] = useState('landing'); return ( <> {/* Inject global styles */} {loading && ( setLoading(false)} /> )} {!loading && ( {view === 'landing' && ( setView('dashboard')} /> )} {view === 'dashboard' && ( )} )} ); }