// ============ NayanTrack bundle (auto-concatenated) ============ const { useState, useEffect, useRef, useMemo } = React; // ---------- app-shell.jsx ---------- // App shell — persona nav, top bar, page routing const SCREENS = [ { id: 'home', label: 'Overview', group: 'Start', crumb: 'NayanTrack / Overview' }, { id: 'calibration', label: 'Calibration', group: 'Capture', crumb: 'Capture / Calibration' }, { id: 'recorder', label: 'Session Recorder', group: 'Capture', crumb: 'Capture / Live Session' }, { id: 'assessment', label: 'Assessment Battery', group: 'Capture', crumb: 'Capture / Assessment' }, { id: 'training', label: 'Vision Training', group: 'Train', crumb: 'Train / Vision Drills' }, { id: 'vr', label: 'VR / AR Training', group: 'Train', crumb: 'Train / VR & AR' }, { id: 'scientist', label: 'Sports Scientist', group: 'Analyze', crumb: 'Analyze / Athlete Profile' }, { id: 'video', label: 'Video Analysis', group: 'Analyze', crumb: 'Analyze / Match Video' }, { id: 'coach', label: 'Coach Portal', group: 'Analyze', crumb: 'Analyze / Squad' }, { id: 'athlete', label: 'Athlete Portal', group: 'Analyze', crumb: 'Analyze / My Performance' }, { id: 'talent', label: 'Talent ID', group: 'Analyze', crumb: 'Analyze / Talent Identification' }, { id: 'medical', label: 'Medical & Rehab', group: 'Analyze', crumb: 'Analyze / Rehabilitation' }, { id: 'centre', label: 'Centre Admin', group: 'Manage', crumb: 'Manage / Centre Ops' }, { id: 'command', label: 'National Command', group: 'Manage', crumb: 'Manage / SAI Command' }, { id: 'lab', label: 'Test Designer', group: 'Manage', crumb: 'Manage / Test Designer' }, { id: 'reports', label: 'Reports & Export', group: 'Manage', crumb: 'Manage / Reports' }, ]; function BrandMark({ size = 28 }) { return (
); } function Sidebar({ current, onNav }) { const groups = ['Start', 'Capture', 'Train', 'Analyze', 'Manage']; return ( ); } function TopBar({ current }) { const meta = SCREENS.find(s => s.id === current) || SCREENS[0]; const [time, setTime] = useState(new Date()); useEffect(() => { const t = setInterval(() => setTime(new Date()), 1000); return () => clearInterval(t); }, []); const tstr = time.toLocaleTimeString('en-IN', { hour12: false }); const showRec = current === 'recorder'; return (
{meta.crumb.split(' / ').map((p, i, arr) => ( {p} {i < arr.length - 1 && /} ))}
{showRec && ( REC · 03:47 )} Tracker Online {tstr} · IST
RM
); } /* ============================= HOME HUB ============================= */ function HomeHub({ onNav }) { const personas = [ { id: 'recorder', num: '01', title: 'Session Recorder', desc: 'Live gaze capture, calibration and event marking during athlete assessment.', tags: ['LIVE', 'GAZE'] }, { id: 'calibration', num: '02', title: 'Calibration', desc: 'Interactive 3/5/9/13-point eye-tracker calibration and accuracy validation.', tags: ['SETUP', 'ACCURACY'] }, { id: 'assessment', num: '03', title: 'Assessment Battery', desc: 'Sports-vision and cognitive test suite — reaction, tracking, decision, memory.', tags: ['VISION', 'COGNITIVE'] }, { id: 'training', num: '04', title: 'Vision Training', desc: 'AI-generated drill library — peripheral, tracking, reflex and decision training.', tags: ['DRILLS', 'REFLEX'] }, { id: 'vr', num: '05', title: 'VR / AR Training', desc: 'Immersive scenario training on eye-tracked headsets with foveated rendering.', tags: ['IMMERSIVE', 'XR'] }, { id: 'scientist', num: '06', title: 'Sports Scientist', desc: 'Deep visual-attention analytics, benchmarking and quiet-eye analysis.', tags: ['ANALYTICS', 'BENCHMARK'] }, { id: 'video', num: '07', title: 'Video Analysis', desc: 'Import match footage and sync gaze, head, player and ball tracking frame-by-frame.', tags: ['FOOTAGE', 'SYNC'] }, { id: 'coach', num: '08', title: 'Coach Portal', desc: 'Squad progress, drill recommendations and week-over-week attention trends.', tags: ['SQUAD', 'DRILLS'] }, { id: 'athlete', num: '09', title: 'Athlete Portal', desc: 'Personal scorecards, streaks, upcoming tests and self-training drills.', tags: ['SCORECARD', 'STREAKS'] }, { id: 'talent', num: '10', title: 'Talent Identification',desc: 'AI ranking of young athletes across the Khelo India pipeline — vision-led scouting.', tags: ['KHELO INDIA', 'RANKING'] }, { id: 'medical', num: '11', title: 'Medical & Rehab', desc: 'Baseline vs post-injury, concussion assessment, return-to-play readiness.', tags: ['REHAB', 'CONCUSSION'] }, { id: 'centre', num: '12', title: 'Centre Administrator', desc: 'Device fleet, calibration health, scheduling and coach adoption at one facility.', tags: ['DEVICES', 'OPS'] }, { id: 'command', num: '13', title: 'National Command', desc: 'Multi-centre KPIs, high-potential athlete alerts and sport-wise distribution.', tags: ['NATIONAL', 'MAP'] }, { id: 'lab', num: '14', title: 'Test Designer', desc: 'Configure sport-specific stimuli, AOIs, scoring rules and normative bands.', tags: ['STIMULI', 'AOI'] }, { id: 'reports', num: '15', title: 'Reports & Export', desc: 'Build athlete, coach, tournament and medical reports — PDF, Excel, dashboards.', tags: ['PDF', 'EXPORT'] }, { id: 'console', num: '16', title: 'Admin Console', desc: 'Audit logs, consent management, RBAC and device provisioning across the platform.', tags: ['SOON'], disabled: true }, ]; return (
NayanTrack नयन
Sports Authority of India · Visual Performance Platform
24 CENTRES ONLINE SAI · CLASSIFIED
━━ Eye tracking · attention · anticipation

See what your
athletes see.
Coach what they miss.

NayanTrack turns gaze, pupil and blink data into decision-quality metrics — quiet-eye, anticipation, peripheral awareness — for cricket, hockey, shooting, archery and ten more Indian sports.

18,240
Athletes Enrolled
1.2M
Gaze Samples / Session
0.48°
Median Accuracy
13 / 24
Sports · Centres
Choose a workspace
16 · MODULES
{personas.map(p => (
!p.disabled && onNav(p.id)} >
/ {p.num}
{p.title}
{p.desc}
{p.tags.map(t => ( {t} ))}
))}
NayanTrack Platform · Build 2026.07 · Bengaluru NCoE
SAI · Confidential · v0.4 Alpha
); } /* ============================= APP ROOT ============================= */ function App() { const [screen, setScreen] = useState(() => { return localStorage.getItem('nt.screen') || 'home'; }); useEffect(() => { localStorage.setItem('nt.screen', screen); }, [screen]); // Home hub has its own layout (no sidebar) if (screen === 'home') { return ; } const ScreenComp = window.NT_SCREENS?.[screen] || (() => (
Loading
Preparing screen…
)); return (
); } Object.assign(window, { App, BrandMark }); // ---------- screens/calibration.jsx ---------- // Calibration Wizard — interactive 3/5/9/13-point eye-tracker calibration const CAL_PATTERNS = { 3: [[50,50],[15,50],[85,50]], 5: [[50,50],[15,15],[85,15],[15,85],[85,85]], 9: [[15,15],[50,15],[85,15],[15,50],[50,50],[85,50],[15,85],[50,85],[85,85]], 13: [[15,15],[50,15],[85,15],[15,50],[50,50],[85,50],[15,85],[50,85],[85,85],[32,32],[68,32],[32,68],[68,68]], }; function qualityColor(q) { if (q == null) return 'var(--fg-4)'; if (q < 0.40) return 'var(--accent)'; if (q < 0.50) return 'var(--cyan)'; if (q < 0.65) return 'var(--saffron)'; return 'var(--red)'; } // Deterministic-ish pseudo quality so re-renders don't jitter each point function seedQuality(i) { const base = [0.42, 0.38, 0.51, 0.44, 0.29, 0.47, 0.55, 0.41, 0.62, 0.36, 0.49, 0.58, 0.33]; return base[i % base.length]; } function CalibrationStage({ pattern, phase, active, results }) { const pts = CAL_PATTERNS[pattern]; return (
{/* faint grid backdrop */} {[20,40,60,80].map(v => )} {[20,40,60,80].map(v => )} {pts.map((p, i) => { const done = results[i] != null; const isActive = phase === 'running' && i === active; const c = done ? qualityColor(results[i]) : isActive ? 'var(--accent)' : 'var(--fg-4)'; return (
{isActive && }
{done &&
{results[i].toFixed(2)}°
}
); })} {/* overlays */}
{phase === 'running' ? CALIBRATING : phase === 'done' ? VALIDATED : READY} {pattern}-POINT · TOBII SPECTRUM · 300 HZ
{phase === 'idle' ? 'FIXATE EACH TARGET · KEEP HEAD STILL' : phase === 'running' ? `TARGET ${active + 1}/${pattern}` : 'ACCEPT OR RE-RUN BELOW'} SCREEN · 1920×1080 · 27"
); } function EyeTraceCard({ eye, deg, conf }) { return (
{eye} EYE {deg.toFixed(2)}°
{/* mock eye + pupil crosshair */}
{/* glints */}
Pupil
3.2 mm
Track Conf.
{conf}%
); } function CalibrationScreen({ onNav }) { const [pattern, setPattern] = useState(9); const [phase, setPhase] = useState('idle'); // idle | running | done const [active, setActive] = useState(0); const [results, setResults] = useState({}); const timer = useRef(null); const pts = CAL_PATTERNS[pattern]; const stop = () => { if (timer.current) clearInterval(timer.current); timer.current = null; }; useEffect(() => stop, []); const reset = (p = pattern) => { stop(); setPattern(p); setPhase('idle'); setActive(0); setResults({}); }; const start = () => { stop(); setResults({}); setActive(0); setPhase('running'); let i = 0; timer.current = setInterval(() => { setResults(r => ({ ...r, [i]: seedQuality(i) + (Math.random() - 0.5) * 0.06 })); i += 1; if (i >= pts.length) { stop(); setPhase('done'); setActive(pts.length - 1); } else { setActive(i); } }, 650); }; const collected = Object.values(results); const avg = collected.length ? (collected.reduce((s, v) => s + v, 0) / collected.length) : null; const worst = collected.length ? Math.max(...collected) : null; const passed = avg != null && avg < 0.55 && worst < 0.75; const progress = Math.round((collected.length / pts.length) * 100); return (
━━ Pre-session setup · Athlete #SAI-BLR-1284
Eye-Tracker Calibration
{[3, 5, 9, 13].map(p => ( ))}
{phase !== 'running' ? : } {passed && }
{/* device banner */}
AP
Arjun Prakash
U-19 · CRICKET NT-LAB-01 · TOBII SPECTRUM
Lab 1 · Bengaluru NCoE · 300 Hz · Binocular · Glasses: none
Progress
{progress}%
{/* Left: stage + validation */}
Validation Result
{phase === 'done' ? {passed ? '✓ PASS' : '△ RETRY ADVISED'} · {avg != null ? avg.toFixed(2) : '—'}° : AWAITING RUN}
Mean Accuracy
{avg != null ? avg.toFixed(2) + '°' : '—'}
Worst Point
{worst != null ? worst.toFixed(2) + '°' : '—'}
Precision (RMS)
{phase === 'done' ? '0.11°' : '—'}
Head Range
±35°
SAI Acceptance Threshold mean < 0.55° · worst < 0.75°
{/* Right: eye traces + per-point + tips */}
Live Eye Tracking
BINOCULAR
Per-Point Accuracy
{collected.length}/{pts.length}
{pts.map((p, i) => (
P{String(i + 1).padStart(2, '0')}
{results[i] != null ? results[i].toFixed(2) + '°' : '—'}
))}
Setup Checklist
{[ ['✓', 'Ambient light 300–500 lux', true], ['✓', 'Eye-to-screen 60–70 cm', true], ['✓', 'No reflective eyewear', true], ['△', 'Head within tracking box', false], ].map((c, i) => (
{c[0]} {c[1]}
))}
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.calibration = CalibrationScreen; // ---------- screens/recorder.jsx ---------- // Session Recorder — live gaze capture + calibration const SPORTS = [ { id: 'cricket', name: 'Cricket', scenario: 'Bowler Release · Anticipation Test' }, { id: 'hockey', name: 'Hockey', scenario: 'Passing-Lane Recognition' }, { id: 'football', name: 'Football', scenario: 'Pre-Reception Scan' }, { id: 'badminton', name: 'Badminton', scenario: 'Shuttle Trajectory Prediction' }, { id: 'archery', name: 'Archery', scenario: 'Quiet-Eye · Aim Stability' }, { id: 'shooting', name: 'Shooting', scenario: 'Target Acquisition Time' }, { id: 'boxing', name: 'Boxing', scenario: 'Punch Anticipation Cues' }, { id: 'tennis', name: 'Tennis', scenario: 'Serve Anticipation' }, { id: 'tt', name: 'Table Tennis', scenario: 'Rapid Gaze Transitions' }, { id: 'kabaddi', name: 'Kabaddi', scenario: 'Peripheral Defender Track' }, { id: 'wrestling', name: 'Wrestling', scenario: 'Movement Prediction' }, { id: 'esports', name: 'Esports', scenario: 'Interface Scan · Fatigue' }, { id: 'para', name: 'Para Sports', scenario: 'Accessible Attention Test' }, ]; /* ============ Gaze scene: animated cursor + trail over placeholder video ============ */ function GazeScene({ sport }) { const canvasRef = useRef(null); const [gaze, setGaze] = useState({ x: 50, y: 50, pupilL: 3.2, pupilR: 3.3 }); const trailRef = useRef([]); // Predefined gaze paths per sport (percent coords) const paths = { cricket: [[35,30],[40,45],[52,55],[60,62],[70,68],[65,55],[55,50],[45,42],[40,38]], hockey: [[20,55],[35,60],[52,50],[65,45],[75,60],[60,70],[45,65],[30,55]], football: [[25,40],[45,35],[60,50],[75,55],[70,70],[50,60],[35,50],[20,45]], archery: [[50,50],[51,50],[50,49],[50,51],[50,50],[49,50],[50,50],[51,49],[50,50]], shooting: [[50,50],[50.5,49.5],[50,50],[49.5,50],[50,50.5],[50,50]], badminton: [[40,25],[55,35],[65,50],[55,65],[45,55],[35,45]], tennis: [[30,40],[50,30],[70,50],[65,65],[45,60],[30,50]], tt: [[35,45],[55,40],[70,50],[60,60],[40,55]], kabaddi: [[25,50],[45,45],[65,55],[75,50],[55,65],[35,60]], boxing: [[45,40],[55,45],[60,50],[50,55],[45,50]], wrestling: [[40,50],[55,55],[65,50],[55,45],[45,50]], esports: [[20,20],[70,25],[75,70],[25,75],[50,50],[80,50],[20,50]], para: [[40,40],[55,50],[60,55],[45,50]], }; useEffect(() => { let t = 0; let raf; const path = paths[sport.id] || paths.cricket; const tick = () => { t += 0.008; const idx = (t * path.length) % path.length; const i0 = Math.floor(idx) % path.length; const i1 = (i0 + 1) % path.length; const f = idx - Math.floor(idx); const [x0, y0] = path[i0]; const [x1, y1] = path[i1]; // slight jitter (saccadic micro-movement) const jitter = () => (Math.random() - 0.5) * 0.4; const x = x0 + (x1 - x0) * f + jitter(); const y = y0 + (y1 - y0) * f + jitter(); setGaze({ x, y, pupilL: 3.2 + Math.sin(t * 3) * 0.15 + (Math.random() - 0.5) * 0.05, pupilR: 3.3 + Math.sin(t * 3 + 0.2) * 0.15 + (Math.random() - 0.5) * 0.05, }); trailRef.current.push({ x, y }); if (trailRef.current.length > 60) trailRef.current.shift(); raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [sport.id]); // Draw trail useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const dpr = window.devicePixelRatio || 1; const rect = canvas.getBoundingClientRect(); canvas.width = rect.width * dpr; canvas.height = rect.height * dpr; const ctx = canvas.getContext('2d'); ctx.scale(dpr, dpr); ctx.clearRect(0, 0, rect.width, rect.height); const pts = trailRef.current; if (pts.length < 2) return; for (let i = 1; i < pts.length; i++) { const alpha = (i / pts.length) * 0.7; const p0 = pts[i - 1]; const p1 = pts[i]; ctx.beginPath(); ctx.strokeStyle = `oklch(0.82 0.14 210 / ${alpha})`; ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.moveTo((p0.x / 100) * rect.width, (p0.y / 100) * rect.height); ctx.lineTo((p1.x / 100) * rect.width, (p1.y / 100) * rect.height); ctx.stroke(); } }, [gaze]); return (
{/* Placeholder "scene" — diagonal stripes with label */}
{/* Sport-specific mock scene diagram */} {/* AOIs (Areas of Interest) — dashed rectangles */} {/* Gaze trail */} {/* Gaze cursor */}
GAZE · {gaze.x.toFixed(1)}, {gaze.y.toFixed(1)}
{/* Corner overlays */}
REC SCENE FEED · 1920×1080 · 240 FPS
{sport.name.toUpperCase()} · TRIAL 07/12
T+00:03.847 · SACCADE +12°/s · FIX #24
PUPIL L {gaze.pupilL.toFixed(2)}mm · R {gaze.pupilR.toFixed(2)}mm
); } function SportSceneDiagram({ sport }) { // Minimal SVG hints to make scenes distinct const common = { position: 'absolute', inset: 0, width: '100%', height: '100%', opacity: 0.6 }; if (sport === 'cricket') { return ( {/* Pitch */} {/* Stumps far */} {/* Bowler figure */} {/* Ball trajectory */} {/* Batsman */} ); } if (sport === 'archery' || sport === 'shooting') { return ( ); } if (sport === 'football' || sport === 'hockey' || sport === 'kabaddi') { return ( {/* Players */} {[[30,30],[45,45],[60,55],[75,35],[95,50],[110,40],[125,55],[40,65],[70,70]].map((p,i)=>( ))} ); } if (sport === 'tennis' || sport === 'badminton' || sport === 'tt') { return ( ); } return null; } function AOIs({ sport }) { const aois = { cricket: [{x:75,y:22,w:12,h:14,l:'RELEASE POINT'},{x:35,y:50,w:22,h:20,l:'BAT/BODY'}], archery: [{x:44,y:44,w:12,h:12,l:'TARGET GOLD'}], shooting: [{x:46,y:46,w:8,h:8,l:'BULLSEYE'}], football: [{x:20,y:35,w:15,h:18,l:'PASS OPT A'},{x:65,y:55,w:15,h:15,l:'DEFENDER'},{x:75,y:25,w:12,h:15,l:'PASS OPT B'}], hockey: [{x:25,y:50,w:15,h:18,l:'BALL CARRIER'},{x:60,y:35,w:15,h:15,l:'LANE'}], kabaddi: [{x:30,y:40,w:15,h:20,l:'RAIDER'},{x:60,y:45,w:20,h:20,l:'DEFENDERS'}], tennis: [{x:22,y:25,w:20,h:35,l:'OPPONENT'},{x:60,y:60,w:15,h:15,l:'BALL LAND'}], badminton:[{x:30,y:20,w:25,h:20,l:'SHUTTLE PEAK'}], tt: [{x:60,y:45,w:15,h:15,l:'BOUNCE'}], boxing: [{x:35,y:30,w:25,h:30,l:'OPPONENT SHOULDERS'}], wrestling:[{x:35,y:35,w:30,h:35,l:'HIPS/GRIP'}], esports: [{x:5,y:5,w:15,h:15,l:'MINIMAP'},{x:75,y:70,w:15,h:15,l:'HUD'},{x:40,y:40,w:20,h:20,l:'CROSSHAIR'}], para: [{x:40,y:40,w:20,h:20,l:'STIMULUS'}], }; const list = aois[sport] || aois.cricket; return ( <> {list.map((a, i) => (
{a.l}
))} ); } /* ============ Live sidebar metrics ============ */ function LiveMeter({ label, value, unit, max = 100, color = 'accent' }) { const pct = Math.min(100, (value / max) * 100); return (
{label}
{typeof value === 'number' ? value.toFixed(1) : value} {unit}
); } function LiveMetrics() { const [t, setT] = useState(0); useEffect(() => { const i = setInterval(() => setT(x => x + 1), 200); return () => clearInterval(i); }, []); const wobble = (base, amp) => base + Math.sin(t / 6) * amp + (Math.random() - 0.5) * amp * 0.3; return (
); } /* ============ Calibration grid ============ */ function CalibrationGrid() { // 9 points on a 3x3 grid with quality scores const points = [ { q: 0.42, x: 15, y: 20 }, { q: 0.38, x: 50, y: 20 }, { q: 0.51, x: 85, y: 20 }, { q: 0.44, x: 15, y: 50 }, { q: 0.29, x: 50, y: 50 }, { q: 0.47, x: 85, y: 50 }, { q: 0.55, x: 15, y: 80 }, { q: 0.41, x: 50, y: 80 }, { q: 0.62, x: 85, y: 80 }, ]; const avg = (points.reduce((s, p) => s + p.q, 0) / points.length).toFixed(2); return (
Calibration · 9-point
PASS · {avg}°
{points.map((p, i) => (
{p.q.toFixed(2)}°
))}
3×3 GRID
Left Eye
0.44°
Right Eye
0.51°
Drift
0.08°
Head Range
±35°
); } /* ============ Sport switcher ============ */ function SportSwitcher({ sport, onChange }) { return (
Assessment Protocol
{sport.name.toUpperCase()}
{SPORTS.map(s => ( ))}
); } /* ============ Athlete info card ============ */ function AthleteBanner() { return (
AP
Arjun Prakash
SAI-BLR-1284 U-19 · CRICKET RIGHT · RIGHT
Age 17 · M · Bengaluru NCoE Session 04 · 15 Jul 2026 · 09:42 IST Tracker · Tobii Pro Spectrum · 300 Hz
); } /* ============ Event log ============ */ function EventLog() { const events = [ { t: '00:03.847', tag: 'FIX', label: 'Fixation → RELEASE POINT', color: 'var(--accent)' }, { t: '00:03.612', tag: 'SAC', label: 'Saccade 12°/s to bowler', color: 'var(--cyan)' }, { t: '00:03.140', tag: 'FIX', label: 'Fixation → BAT/BODY', color: 'var(--accent)' }, { t: '00:02.980', tag: 'RSP', label: 'Response · CORRECT (short-length)', color: 'var(--green)' }, { t: '00:02.740', tag: 'BLNK', label: 'Blink · 87ms', color: 'var(--fg-2)' }, { t: '00:02.410', tag: 'STIM', label: 'Trial 07 · stimulus onset', color: 'var(--saffron)' }, { t: '00:01.980', tag: 'SAC', label: 'Saccade 28°/s to release', color: 'var(--cyan)' }, { t: '00:01.610', tag: 'FIX', label: 'Fixation → RELEASE POINT', color: 'var(--accent)' }, ]; return (
Event Stream
LIVE
{events.map((e, i) => (
{e.t} {e.tag} {e.label}
))}
); } /* ============ Main screen ============ */ function RecorderScreen() { const [sport, setSport] = useState(SPORTS[0]); return (
━━ Live capture · session 04
Session Recorder
Duration
03:47.28
Samples
68,412
Trials
7/12
Live Metrics
@ 300Hz
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.recorder = RecorderScreen; // ---------- screens/assessment.jsx ---------- // Assessment Battery — sports-vision + cognitive test suite const VISION_TESTS = [ { t: 'Static Visual Acuity', v: '20/12', p: 94, st: 'done' }, { t: 'Dynamic Visual Acuity', v: '20/18', p: 88, st: 'done' }, { t: 'Peripheral Vision', v: '184°', p: 71, st: 'watch' }, { t: 'Depth Perception', v: '22"arc', p: 90, st: 'done' }, { t: 'Contrast Sensitivity', v: '2.1', p: 86, st: 'done' }, { t: 'Eye–Hand Coordination', v: '312ms', p: 82, st: 'done' }, { t: 'Eye–Foot Coordination', v: '358ms', p: 77, st: 'done' }, { t: 'Visual Memory', v: '9/10', p: 91, st: 'done' }, { t: 'Multiple Object Tracking',v: '5 obj', p: 84, st: 'active' }, { t: 'Anticipation Ability', v: '—', p: 0, st: 'pending' }, { t: 'Visual Search Speed', v: '—', p: 0, st: 'pending' }, { t: 'Decision Time', v: '—', p: 0, st: 'pending' }, ]; const COGNITIVE_TESTS = [ { t: 'Reaction Time', v: '248ms', p: 89, st: 'done' }, { t: 'Choice Reaction', v: '412ms', p: 81, st: 'done' }, { t: 'Working Memory', v: '7 span',p: 85, st: 'done' }, { t: 'Focus', v: '92%', p: 88, st: 'done' }, { t: 'Concentration', v: '87%', p: 80, st: 'done' }, { t: 'Processing Speed', v: '1.8/s', p: 83, st: 'done' }, { t: 'Attention Switching', v: '540ms', p: 74, st: 'watch' }, { t: 'Inhibitory Control', v: '94%', p: 90, st: 'done' }, { t: 'Executive Function', v: '78', p: 79, st: 'done' }, { t: 'Mental Fatigue', v: 'Low', p: 86, st: 'done' }, { t: 'Decision Accuracy', v: '88%', p: 84, st: 'active' }, ]; function pctColor(p) { if (p >= 85) return 'var(--accent)'; if (p >= 75) return 'var(--cyan)'; if (p > 0) return 'var(--saffron)'; return 'var(--fg-4)'; } function TestCard({ test }) { const statusMap = { done: , active: LIVE, watch: , pending: QUEUED, }; return (
{test.t}
{statusMap[test.st]}
{test.v} {test.p ? test.p + '%ile' : ''}
); } // Live choice-reaction runner — target lights in one of 6 zones, RT ticks function LiveTestRunner() { const [lit, setLit] = useState(2); const [rt, setRt] = useState(248); const [trial, setTrial] = useState(7); useEffect(() => { const i = setInterval(() => { setLit(Math.floor(Math.random() * 6)); setRt(220 + Math.floor(Math.random() * 90)); setTrial(t => (t % 12) + 1); }, 1100); return () => clearInterval(i); }, []); return (
Now Running · Choice Reaction
TRIAL {trial}/12
{Array.from({ length: 6 }, (_, i) => (
))}
GO / NO-GO · CENTRAL FIXATION
{rt}ms
Mean RT
248ms
Accuracy
11/12
False Starts
1
); } function AssessmentScreen({ onNav }) { const done = [...VISION_TESTS, ...COGNITIVE_TESTS].filter(t => t.st === 'done' || t.st === 'watch').length; const total = VISION_TESTS.length + COGNITIVE_TESTS.length; return (
━━ Baseline battery · Arjun Prakash · Session 04
Assessment Battery
{/* KPI row */}
Tests Completed
{done}/ {total}
{Math.round((done / total) * 100)}% · ~14 min left
Visual Performance Score
86
▲ +4 vs baseline
Reaction Index
248ms
▲ 89th pctl
Visual IQ
128
Cognitive composite
{/* Test catalog */}
Sports Vision Assessment · 12 tests
MODULE 03
{VISION_TESTS.map((t, i) => )}
Cognitive Performance · 11 tests
MODULE 04
{COGNITIVE_TESTS.map((t, i) => )}
{/* Live runner + summary */}
Battery Protocol
SAI STANDARD
{[ { l: 'Sports Vision block', s: '8/12 done', c: 'var(--accent)' }, { l: 'Cognitive block', s: '9/11 done', c: 'var(--accent)' }, { l: 'Sport-specific (Cricket)', s: 'queued', c: 'var(--fg-3)' }, { l: 'Fatigue re-test', s: 'queued', c: 'var(--fg-3)' }, ].map((r, i) => (
{r.l} {r.s}
))}
◆ AI Note
Peripheral vision (71st pctl) and attention switching (74th) trail this athlete's other measures. Recommend the Peripheral Cue Detection and Task-Switch drills before the next retest.
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.assessment = AssessmentScreen; // ---------- screens/training.jsx ---------- // Vision Training Studio — AI drill library + live reflex board const TRAIN_DRILLS = [ { t: 'Peripheral Cue Detection', cat: 'PERIPHERAL', dur: '12 min', diff: 3, sport: 'All', done: 74 }, { t: 'Multiple Object Tracking', cat: 'TRACKING', dur: '15 min', diff: 4, sport: 'Team', done: 61 }, { t: 'Multiple Ball Tracking', cat: 'TRACKING', dur: '10 min', diff: 4, sport: 'Cricket', done: 55 }, { t: 'Color Recognition', cat: 'RECOGNITION',dur: '6 min', diff: 2, sport: 'All', done: 88 }, { t: 'Speed Recognition', cat: 'RECOGNITION',dur: '8 min', diff: 3, sport: 'Racket', done: 70 }, { t: 'Dynamic Target Training', cat: 'TARGET', dur: '14 min', diff: 4, sport: 'Shooting', done: 66 }, { t: 'Light Board Reflex', cat: 'REFLEX', dur: '9 min', diff: 3, sport: 'All', done: 82 }, { t: 'Reflex Reaction Grid', cat: 'REFLEX', dur: '7 min', diff: 2, sport: 'Boxing', done: 79 }, { t: 'Decision Training', cat: 'DECISION', dur: '16 min', diff: 5, sport: 'Team', done: 48 }, { t: 'Quiet-Eye Fixation', cat: 'FIXATION', dur: '10 min', diff: 3, sport: 'Archery', done: 90 }, { t: 'Anticipation Video', cat: 'ANTICIPATE', dur: '20 min', diff: 4, sport: 'Cricket', done: 52 }, { t: 'Distraction Resistance', cat: 'FOCUS', dur: '12 min', diff: 3, sport: 'All', done: 64 }, ]; const CATS = ['ALL', 'PERIPHERAL', 'TRACKING', 'REFLEX', 'DECISION', 'FIXATION']; function Difficulty({ n }) { return ( {[1,2,3,4,5].map(i => ( ))} ); } // Live "light board" — cells illuminate in sequence, athlete taps them function LightBoard() { const [lit, setLit] = useState([5, 11]); const [hits, setHits] = useState(0); useEffect(() => { const i = setInterval(() => { const a = Math.floor(Math.random() * 16); let b = Math.floor(Math.random() * 16); if (b === a) b = (b + 1) % 16; setLit([a, b]); setHits(h => h + 1); }, 850); return () => clearInterval(i); }, []); return (
{Array.from({ length: 16 }, (_, i) => { const on = lit.includes(i); return (
); })}
); } function TrainingScreen({ onNav }) { const [cat, setCat] = useState('ALL'); const filtered = cat === 'ALL' ? TRAIN_DRILLS : TRAIN_DRILLS.filter(d => d.cat === cat); return (
━━ AI-generated drills · 10 categories
Vision Training Studio
{/* KPI row */}
Drill Library
42
10 categories · 13 sports
Assigned · This Week
6
▲ 4 completed · 67%
Training Minutes · MTD
284
▲ +38 vs last month
Avg Improvement
+7.2%
peripheral +11%
{/* Drill library */}
Drill Library
{CATS.map(c => ( ))}
{filtered.map((d, i) => (
◆ {d.cat}
{d.t}
{d.dur} · {d.sport}
Mastery {d.done}%
))}
{/* Live drill + plan */}
Live · Light Board Reflex
ROUND 3
Hits
47
Avg RT
412ms
Streak
12
This Week's Plan
6 DRILLS
{[ { t: 'Peripheral Cue Detection', d: 'Mon · done', ok: true }, { t: 'Multiple Object Tracking', d: 'Tue · done', ok: true }, { t: 'Decision Training', d: 'Wed · today', ok: false }, { t: 'Reflex Reaction Grid', d: 'Thu', ok: false }, { t: 'Anticipation Video', d: 'Fri', ok: false }, ].map((r, i) => (
{r.t} {r.ok ? '✓ ' : ''}{r.d}
))}
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.training = TrainingScreen; // ---------- screens/vr.jsx ---------- // VR / AR Training — immersive scenario training with eye-tracked headsets const VR_SCENARIOS = [ { t: 'Penalty Simulation', sport: 'Football', dev: 'Quest 3', diff: 4, active: true }, { t: 'Cricket Batting', sport: 'Cricket', dev: 'Quest Pro', diff: 5 }, { t: 'Goalkeeper Vision', sport: 'Football', dev: 'Vive Focus', diff: 4 }, { t: 'Tennis Return', sport: 'Tennis', dev: 'Quest 3', diff: 3 }, { t: 'Hockey Goalkeeping', sport: 'Hockey', dev: 'Vision Pro', diff: 4 }, { t: 'Boxing Reaction', sport: 'Boxing', dev: 'Quest Pro', diff: 5 }, { t: 'Shooting Stability', sport: 'Shooting', dev: 'Vive Focus', diff: 3 }, { t: 'Archery Steadiness', sport: 'Archery', dev: 'Vision Pro', diff: 3 }, ]; const HEADSETS = [ { id: 'Meta Quest 3', n: 2, st: 'ok' }, { id: 'Meta Quest Pro', n: 2, st: 'ok' }, { id: 'HTC Vive Focus', n: 1, st: 'ok' }, { id: 'Apple Vision Pro', n: 1, st: 'charging' }, { id: 'Pico / OpenXR', n: 1, st: 'offline' }, ]; // First-person penalty scene with animated eye-tracked reticle + foveation ring function HeadsetView() { const [g, setG] = useState({ x: 50, y: 46 }); useEffect(() => { const path = [[50,46],[36,42],[62,40],[54,52],[44,48],[58,45]]; let t = 0, raf; const tick = () => { t += 0.006; const idx = (t * path.length) % path.length; const i0 = Math.floor(idx) % path.length, i1 = (i0 + 1) % path.length, f = idx - Math.floor(idx); setG({ x: path[i0][0] + (path[i1][0] - path[i0][0]) * f + (Math.random() - 0.5) * 0.5, y: path[i0][1] + (path[i1][1] - path[i0][1]) * f + (Math.random() - 0.5) * 0.5, }); raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, []); return (
{/* Stadium / pitch scene */} {/* ground */} {[0,1,2,3,4].map(i => )} {/* goal frame */} {/* net hint */} {[64,68,72,76,80,84,88,92,96].map(x => )} {[40,44,48,52].map(y => )} {/* keeper */} {/* ball */} {/* trajectory */} {/* foveation ring around gaze */}
{/* gaze reticle */}
{/* HUD */}
VR LIVE PENALTY SIM · QUEST 3 · 90 FPS · FOVEATED
SHOT 07/15
GAZE {g.x.toFixed(0)},{g.y.toFixed(0)} · IPD 63mm DIVE READ · +0.34s EARLIER
); } function VRScreen({ onNav }) { const [t, setT] = useState(0); useEffect(() => { const i = setInterval(() => setT(x => x + 1), 900); return () => clearInterval(i); }, []); const hr = 118 + Math.round(Math.sin(t / 3) * 6); return (
━━ Immersive training · Arjun Prakash
VR / AR Training
{/* KPI row */}
Headsets Online
6/ 7
Quest · Vive · Vision Pro
Scenarios
18
8 sports · OpenXR
Anticipation Gain
+0.34s
▲ earlier dive-read
Foveation Efficiency
3.1×
GPU savings · gaze-driven
{/* Headset view + scenario library */}
Scenario Library
MODULE 11 · VR / AR
{VR_SCENARIOS.map((s, i) => (
◈ {s.dev} {s.active && LOADED}
{s.t}
{s.sport}
))}
{/* Live metrics + fleet */}
Live Session · Biometrics
REC
Heart Rate
{hr}bpm
Immersion
High
Gaze-on-Ball
78%
Motion Comfort
OK
Headset Fleet
6 READY
{HEADSETS.map((h, i) => (
{h.id}
{h.n} unit{h.n > 1 ? 's' : ''}
{h.st === 'ok' && ◆ READY} {h.st === 'charging' && ⚡ CHARGING} {h.st === 'offline' && ◯ OFFLINE}
))}
◈ Transfer Note
VR penalty-read gains transfer to on-field: dive-decision now begins 0.34 s earlier than baseline. Continue 2 sessions/week; re-test on-field in the Recorder.
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.vr = VRScreen; // ---------- screens/scientist.jsx ---------- // Sports Scientist — deep analytics for one athlete /* ============ Heatmap over scene ============ */ function Heatmap() { // Concentrated hotspots over an archery target (quiet-eye canonical example) const hotspots = [ { x: 50, y: 48, r: 8, i: 1.0 }, { x: 49, y: 47, r: 5, i: 0.9 }, { x: 52, y: 51, r: 6, i: 0.7 }, { x: 45, y: 40, r: 4, i: 0.4 }, { x: 58, y: 55, r: 3, i: 0.3 }, { x: 30, y: 30, r: 3, i: 0.2 }, { x: 70, y: 65, r: 3, i: 0.2 }, ]; return (
{/* Archery target */} {/* Heat blobs */} {hotspots.map((h, i) => ( ))} {/* Overlay labels */}
HEATMAP · 12 TRIALS AGGREGATE
LOW
HIGH
); } /* ============ Radar chart of composite indicators ============ */ function RadarChart() { const metrics = [ { label: 'Quiet Eye', athlete: 78, elite: 88 }, { label: 'Anticipation', athlete: 82, elite: 90 }, { label: 'Search Efficiency', athlete: 74, elite: 85 }, { label: 'Peripheral', athlete: 65, elite: 82 }, { label: 'Attention Stab.', athlete: 88, elite: 91 }, { label: 'Decision Speed', athlete: 71, elite: 87 }, { label: 'Gaze Economy', athlete: 80, elite: 86 }, { label: 'Consistency', athlete: 76, elite: 88 }, ]; const cx = 160, cy = 160, R = 120; const N = metrics.length; const pointAt = (i, r) => { const a = (i / N) * Math.PI * 2 - Math.PI / 2; return [cx + Math.cos(a) * r, cy + Math.sin(a) * r]; }; const polyPoints = (values) => values.map((v, i) => pointAt(i, (v / 100) * R).join(',')).join(' '); return ( {/* Grid rings */} {[0.25, 0.5, 0.75, 1].map(f => ( pointAt(i, R * f).join(',')).join(' ')} fill="none" stroke="var(--line)" strokeWidth="1" /> ))} {/* Spokes */} {metrics.map((_, i) => { const [x, y] = pointAt(i, R); return ; })} {/* Elite ghost */} m.elite))} fill="oklch(0.82 0.14 210 / 0.1)" stroke="oklch(0.82 0.14 210)" strokeWidth="1" strokeDasharray="3 3" /> {/* Athlete */} m.athlete))} fill="oklch(0.92 0.19 115 / 0.25)" stroke="oklch(0.92 0.19 115)" strokeWidth="2" /> {/* Athlete points */} {metrics.map((m, i) => { const [x, y] = pointAt(i, (m.athlete / 100) * R); return ; })} {/* Labels */} {metrics.map((m, i) => { const [x, y] = pointAt(i, R + 22); return ( {m.label.toUpperCase()} {m.athlete} ); })} ); } /* ============ Fixation timeline ============ */ function FixationTimeline() { const total = 8.0; // 8 seconds const aois = ['RELEASE', 'BAT', 'PITCH', 'FIELDER']; // Fixation blocks const fixations = [ { aoi: 0, start: 0.2, dur: 0.4 }, { aoi: 2, start: 0.7, dur: 0.3 }, { aoi: 0, start: 1.1, dur: 0.5 }, { aoi: 1, start: 1.8, dur: 0.4 }, { aoi: 0, start: 2.3, dur: 0.6 }, { aoi: 2, start: 3.0, dur: 0.3 }, { aoi: 0, start: 3.4, dur: 0.7 }, { aoi: 1, start: 4.2, dur: 0.5 }, { aoi: 0, start: 4.8, dur: 0.8 }, { aoi: 3, start: 5.7, dur: 0.4 }, { aoi: 0, start: 6.2, dur: 0.5 }, { aoi: 1, start: 6.8, dur: 0.4 }, { aoi: 0, start: 7.3, dur: 0.6 }, ]; const colors = ['var(--accent)', 'var(--cyan)', 'var(--saffron)', 'var(--purple)']; return (
{aois.map((aoi, i) => (
{aoi}
{fixations.filter(f => f.aoi === i).map((f, j) => (
))}
))} {/* Time axis */}
{[0, 2, 4, 6, 8].map(t => {t.toFixed(1)}s)}
{/* Event markers */}
EVENT
{[ { t: 0.1, l: 'STIM' }, { t: 2.4, l: 'BALL RELEASE' }, { t: 6.5, l: 'BAT CONTACT' }, ].map((e, i) => (
{e.l}
))}
); } /* ============ Pupil / cognitive load timeline ============ */ function PupilChart() { const pts = Array.from({ length: 80 }, (_, i) => { const t = i / 80; return 3.2 + Math.sin(t * 6) * 0.4 + Math.sin(t * 14) * 0.15 + t * 0.6; }); const max = Math.max(...pts), min = Math.min(...pts); const norm = pts.map(p => 1 - (p - min) / (max - min)); const points = norm.map((v, i) => `${(i / (norm.length - 1)) * 100},${v * 90 + 5}`).join(' '); return ( {/* Grid lines */} {[25, 50, 75].map(y => ( ))} ); } /* ============ Comparison bars ============ */ function CompareBar({ label, athlete, elite, unit = '', invert = false }) { const max = Math.max(athlete, elite) * 1.2; const winning = invert ? athlete < elite : athlete > elite * 0.9; return (
{label} {athlete}{unit} {' vs '} {elite}{unit}
); } /* ============ Session history sparkline ============ */ function SessionTrend() { const sessions = [72, 74, 71, 76, 78, 80, 79, 82, 81, 84, 86]; const max = 100, min = 60; const w = 100, h = 40; const points = sessions.map((v, i) => `${(i / (sessions.length - 1)) * w},${h - ((v - min) / (max - min)) * h}`).join(' '); return (
{sessions.map((v, i) => ( ))}
S-01 S-11 · TODAY
); } /* ============ Main screen ============ */ function ScientistScreen() { return (
━━ Athlete profile · report 04
Visual Performance Analysis
{/* Athlete banner + composite score */}
MK
Meera Krishnan
ELITE · ARCHERY SAI-PUN-0472
21 F · Pune NCoE · Right dominant · 11 sessions · 2024–2026
Composite Score
84/100
▲ +6 vs baseline · 92nd pctl
Trend · 11 Sessions
{/* KPI row */}
Quiet Eye
1.24s
▲ +180ms vs baseline
Reaction Time
248ms
▲ 12ms faster
Aim-Point Deviation
0.42°
▲ tighter than elite
Cognitive Load
Low
Pupil Δ 0.18mm
{/* Row 1: Heatmap + Radar */}
Gaze Heatmap · Archery Target
HEATMAP TRAIL FIXATION SACCADE
Fixations
142
Avg Fix. Dur.
312ms
Saccades
138
Blinks
44
Composite Indicators
Athlete Elite Avg
{/* Row 2: Timeline + Pupil */}
Fixation Sequence · Trial 07
8.0s · 4 AOIs
Pupil / Cognitive Load
+18% ONSET
Baseline
3.14mm
Peak
3.72mm
Δ Load
0.58
{/* Row 3: Benchmark + AI insights */}
Benchmark · vs Elite Recurve (n=42)
92ND PCTL
AI Interpretation · Explainable
COACH REVIEW
{[ { tag: 'STRENGTH', color: 'var(--accent)', title: 'Exceptional aim-point stability', body: 'Final 800ms before release shows deviation of 0.42° — 18% tighter than elite median. Consistent across 11 of 12 trials.' }, { tag: 'STRENGTH', color: 'var(--accent)', title: 'Quiet-eye onset earlier than baseline', body: 'First stable fixation begins 180ms earlier than session 01. Indicates improved pre-shot routine.' }, { tag: 'WATCH', color: 'var(--saffron)', title: 'First fixation slightly delayed', body: '17ms slower than elite average on target acquisition. Suggests visual search inefficiency at trial onset.' }, { tag: 'CAUTION', color: 'var(--red)', title: 'Blink suppression below elite band', body: 'Two blink events within the 300ms pre-release window on trials 04 and 09. Recommend blink-timing drill.' }, ].map((n, i) => (
◆ {n.tag} {n.title}
{n.body}
))}
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.scientist = ScientistScreen; // ---------- screens/video.jsx ---------- // Match Video Analysis — import footage, sync gaze + ball + player tracking const CLIPS = [ { t: 'Ranji QF · vs MH · Over 14', src: 'BROADCAST', dur: '0:48', active: true }, { t: 'Net practice · bouncer set', src: 'PRACTICE', dur: '2:12' }, { t: 'Drone · field spacing', src: 'DRONE', dur: '1:36' }, { t: 'Slip-catch reaction reel', src: 'TRAINING', dur: '0:54' }, { t: 'Spin anticipation montage', src: 'BROADCAST', dur: '1:20' }, ]; const SYNC_LAYERS = [ { l: 'Eye Movement', c: 'var(--cyan)', on: true }, { l: 'Head Movement', c: 'var(--purple)', on: true }, { l: 'Player Position', c: 'var(--saffron)', on: true }, { l: 'Ball Trajectory', c: 'var(--accent)', on: true }, { l: 'Event Timeline', c: 'var(--red)', on: true }, ]; function VideoStage({ playing }) { const [p, setP] = useState(0.42); // playhead 0..1 const [ball, setBall] = useState({ x: 52, y: 60 }); const [gaze, setGaze] = useState({ x: 50, y: 40 }); useEffect(() => { if (!playing) return; let raf, t = p; const tick = () => { t += 0.0025; if (t > 1) t = 0; setP(t); // ball follows a delivery arc; gaze leads slightly const bx = 22 + t * 60, by = 30 + Math.sin(t * Math.PI) * -22 + 40; setBall({ x: bx, y: by }); setGaze({ x: bx + 6 + (Math.random() - 0.5) * 2, y: by - 6 + (Math.random() - 0.5) * 2 }); raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [playing]); const players = [[30, 66], [70, 50], [58, 72]]; return (
{/* pitch backdrop */}
{/* player tracking boxes */} {players.map((pl, i) => (
P{i + 1} · 0.9{i + 2}
))} {/* ball tracker */}
BALL 138 KM/H
{/* gaze */}
{/* HUD */}
BROADCAST · 1080p50 · SYNCED
GAZE↔BALL Δ 0.18s
{/* scrub bar */}
{[0.18, 0.42, 0.61, 0.83].map((m, i) => (
))}
00:{String(Math.floor(p * 48)).padStart(2, '0')} / 00:48 BALL RELEASE · FIX · BAT CONTACT · APPEAL
); } function VideoScreen({ onNav }) { const [playing, setPlaying] = useState(true); return (
━━ Meera Krishnan · Ranji QF review
Match Video Analysis
{/* import source chips */}
SOURCES {['Broadcast', 'Practice', 'Drone', 'Training'].map((s, i) => ( {s} ))} AI SYNC · EYE · HEAD · PLAYER · BALL · EVENTS
{/* Video + tracks */}
{/* synchronized tracks */}
Synchronized Tracks · 0:48
5 LAYERS
{SYNC_LAYERS.map((ly, i) => (
{ly.l}
{ly.l === 'Event Timeline' ? [0.18, 0.42, 0.61, 0.83].map((m, j) =>
) : Array.from({ length: 24 }, (_, j) => { const h = 4 + Math.abs(Math.sin(j * 0.7 + i)) * 11; return
; })}
))}
{/* Right: clips + insights */}
Clip Library
5 CLIPS
{CLIPS.map((c, i) => (
{c.t}
{c.src} · {c.dur}
))}
Frame Metrics
@ 00:20
Ball Speed
138 km/h
Gaze↔Ball Lag
0.18s
Head Yaw
14°
Tracked Objects
4
◆ AI Sync Insight
On the 00:20 delivery the batter's gaze tracked the ball with an 0.18 s lag — 40 ms tighter than her season average. Head rotation led the eyes, indicating good pre-movement anticipation.
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.video = VideoScreen; // ---------- screens/coach.jsx ---------- // Coach Portal — squad progress, drill recommendations const SQUAD = [ { id: 'AP', name: 'Arjun Prakash', sport: 'Cricket', score: 78, delta: +4, drills: 2, status: 'ON TRACK', flag: null }, { id: 'MK', name: 'Meera Krishnan', sport: 'Archery', score: 84, delta: +6, drills: 1, status: 'ELITE', flag: 'star' }, { id: 'RS', name: 'Rohan Shetty', sport: 'Hockey', score: 71, delta: -2, drills: 3, status: 'WATCH', flag: 'watch' }, { id: 'PP', name: 'Priya Patel', sport: 'Badminton', score: 76, delta: +1, drills: 2, status: 'ON TRACK', flag: null }, { id: 'VK', name: 'Vikram Kumar', sport: 'Shooting', score: 82, delta: +3, drills: 0, status: 'ELITE', flag: 'star' }, { id: 'AN', name: 'Ananya Nair', sport: 'Tennis', score: 69, delta: -5, drills: 4, status: 'AT RISK', flag: 'risk' }, { id: 'SG', name: 'Suresh Ganesan', sport: 'Cricket', score: 73, delta: +2, drills: 2, status: 'ON TRACK', flag: null }, { id: 'RD', name: 'Riya Deshmukh', sport: 'Kabaddi', score: 80, delta: +5, drills: 1, status: 'ELITE', flag: 'star' }, { id: 'HG', name: 'Harpreet Gill', sport: 'Boxing', score: 68, delta: -1, drills: 3, status: 'WATCH', flag: 'watch' }, ]; const DRILLS = [ { title: 'Peripheral Cue Detection', dur: '12 min', sport: 'Hockey · Cricket', athletes: 4, tag: 'PERIPHERAL' }, { title: 'Quiet-Eye Fixation Training', dur: '8 min', sport: 'Archery · Shooting', athletes: 2, tag: 'QUIET EYE' }, { title: 'Multi-Object Tracking', dur: '15 min', sport: 'Team sports', athletes: 6, tag: 'TRACKING' }, { title: 'Serve Anticipation Video', dur: '20 min', sport: 'Tennis · Badminton', athletes: 3, tag: 'ANTICIPATION' }, { title: 'Distraction Resistance', dur: '10 min', sport: 'All', athletes: 5, tag: 'FOCUS' }, ]; function StatusChip({ status }) { const map = { 'ELITE': { cls: 'accent' }, 'ON TRACK': { cls: 'cyan' }, 'WATCH': { cls: 'saffron' }, 'AT RISK': { cls: 'red' }, }; const m = map[status] || {}; return {status}; } function MiniSpark({ values, color = 'var(--accent)' }) { const max = Math.max(...values), min = Math.min(...values); const w = 60, h = 20; const range = max - min || 1; const pts = values.map((v, i) => `${(i / (values.length - 1)) * w},${h - ((v - min) / range) * h}`).join(' '); return ( ); } function CoachScreen({ onNav }) { return (
━━ Coach K. Iyengar · Squad view
Bengaluru Cricket & All-Sports Squad
{/* KPI row */}
Squad Size
28
9 sports · 6 elite
Avg Attention Score
75.4
▲ +2.1 wk-over-wk
Drills Assigned · This Week
18
14 completed · 78%
Athletes At Risk
2
▼ Attention drop > 5pt
{/* Squad table */}
Squad · Attention Trajectory
ALL ELITE AT RISK CRICKET
{SQUAD.map(a => ( onNav('scientist')}> ))}
Athlete Sport Score 4-Wk Trend Δ Week Drills Status
{a.id}
{a.name} {a.flag === 'star' && }
{a.sport} {a.score} a.score - 8 + i + (Math.random() - 0.5) * 4)} color={a.delta >= 0 ? 'var(--accent)' : 'var(--red)'} /> = 0 ? 'var(--accent)' : 'var(--red)' }}> {a.delta >= 0 ? '▲' : '▼'} {Math.abs(a.delta)} {a.drills}
{/* Recommended drills */}
AI Drill Recommendations
5 NEW
{DRILLS.map((d, i) => (
{d.title}
{d.tag}
{d.dur} · {d.sport}
{d.athletes} ATHLETES
))}
Today's Schedule
{[ { t: '09:00', a: 'M. Krishnan', p: 'Archery · Full Assessment', dur: '45m' }, { t: '10:30', a: 'A. Prakash', p: 'Cricket · Anticipation', dur: '30m' }, { t: '13:00', a: 'Squad (6)', p: 'Peripheral Cue Drill', dur: '20m' }, { t: '15:00', a: 'A. Nair', p: 'Tennis · Rehab check-in', dur: '25m' }, ].map((s, i) => (
{s.t}
{s.a}
{s.p}
{s.dur}
))}
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.coach = CoachScreen; // ---------- screens/athlete.jsx ---------- // Athlete Portal — personal scorecard, streaks, drills function ScoreDial({ value, max = 100, size = 200, label }) { const R = size / 2 - 12; const C = 2 * Math.PI * R; const pct = value / max; return ( {value} {label} ); } function Streak() { const days = Array.from({ length: 28 }, (_, i) => { const active = i < 24 && Math.random() > 0.15; const intensity = active ? Math.random() * 0.7 + 0.3 : 0; return { active, intensity }; }); return (
{days.map((d, i) => (
))}
); } function AthleteScreen({ onNav }) { return (
━━ नमस्ते, Arjun · Session 04 complete
Your Vision Report
{/* Big score */}
▲ +4 vs LAST WEEK
You're in the top 18% of U-19 cricketers nationally.
Your bowler tracking has improved sharply. Focus this week on peripheral awareness — that's holding your score back.
Streak
17d
Sessions
04
Level
B+
{/* What you did well / to improve */}
✓ What you did well
Release-point fixation — you found the bowler's hand 40ms faster than last session.
Reaction time — 248ms on choice-reaction, personal best.
▲ To improve
Peripheral awareness — missed 3 of 8 wide-field cues.
Blink control — 2 blinks during ball flight. Coach suggests blink-timing drill.
{/* Drills row */}
Your Drills · Week 03
3 REMAINING
{[ { t: 'Peripheral Cue Detection', d: '12 min', done: true, today: false, tag: 'PERIPHERAL' }, { t: 'Multi-Object Tracking', d: '15 min', done: false, today: true, tag: 'TRACKING' }, { t: 'Blink Timing Drill', d: '8 min', done: false, today: false, tag: 'CONTROL' }, { t: 'Bowler Anticipation Video', d: '20 min', done: true, today: false, tag: 'ANTICIPATE' }, { t: 'Quiet-Eye Fixation', d: '10 min', done: false, today: false, tag: 'FIXATION' }, { t: 'Distraction Resistance', d: '12 min', done: false, today: false, tag: 'FOCUS' }, ].map((d, i) => (
{d.today && TODAY} {d.done && ✓ DONE}
◆ {d.tag}
{d.t}
{d.d}
{!d.done && ( )}
))}
28-Day Streak
17 · PERSONAL BEST
Next milestone
30-day badge · 13 days to go
{/* Upcoming + achievements */}
Upcoming Assessments
{[ { d: 'TUE · 21 JUL', t: '10:30', p: 'Cricket · Bowler anticipation retest', loc: 'Bengaluru NCoE · Lab 2' }, { d: 'FRI · 24 JUL', t: '14:00', p: 'Peripheral awareness batch', loc: 'Bengaluru NCoE · Lab 1' }, { d: 'MON · 27 JUL', t: '09:00', p: 'Talent-ID panel review', loc: 'Regional · Virtual' }, ].map((s, i) => (
{s.d}
{s.t}
{s.p}
{s.loc}
))}
Achievements
{[ { i: '★', l: 'First 250ms', d: 'Sub-250ms reaction', got: true }, { i: '◈', l: '10-Day Streak', d: 'Trained daily', got: true }, { i: '◉', l: 'Bowler Sniper', d: '95% release-point', got: true }, { i: '▲', l: 'Top 20 U-19', d: 'National ranking', got: true }, { i: '◆', l: 'Quiet Master', d: '1.5s quiet-eye', got: false }, { i: '◇', l: '30-Day', d: 'Streak milestone', got: false }, { i: '☆', l: 'Peripheral', d: '90% wide cues', got: false }, { i: '⬢', l: 'Elite Match', d: 'Match elite band', got: false }, ].map((b, i) => (
{b.i}
{b.l.toUpperCase()}
{b.d}
))}
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.athlete = AthleteScreen; // ---------- screens/talent.jsx ---------- // Talent Identification — AI ranking of young athletes across the pipeline const FUNNEL = [ { l: 'School Competitions', v: 48200, c: 'var(--fg-2)' }, { l: 'District Screening', v: 18600, c: 'var(--cyan)' }, { l: 'Khelo India Pool', v: 6240, c: 'var(--cyan)' }, { l: 'Academy Intake', v: 1820, c: 'var(--accent)' }, { l: 'NCoE High-Potential', v: 247, c: 'var(--accent)' }, ]; // vision, reflex, tracking, decision, coordination const PROSPECTS = [ { n: 'Aditya Rane', age: 15, sport: 'Cricket', region: 'Maharashtra', s: [92, 88, 90, 85, 87], comp: 91, tag: 'ELITE' }, { n: 'Sneha Barman', age: 14, sport: 'Archery', region: 'Assam', s: [95, 82, 91, 89, 84], comp: 90, tag: 'ELITE' }, { n: 'Karan Bhullar', age: 16, sport: 'Boxing', region: 'Punjab', s: [84, 94, 86, 82, 90], comp: 88, tag: 'RISING' }, { n: 'Divya Menon', age: 15, sport: 'Badminton', region: 'Kerala', s: [88, 90, 92, 80, 83], comp: 87, tag: 'RISING' }, { n: 'Rohit Yadav', age: 13, sport: 'Shooting', region: 'UP', s: [90, 79, 88, 91, 78], comp: 86, tag: 'RISING' }, { n: 'Tara Singh', age: 16, sport: 'Hockey', region: 'Haryana', s: [82, 86, 89, 84, 88], comp: 85, tag: 'WATCH' }, { n: 'Ishaan Nair', age: 14, sport: 'Football', region: 'Goa', s: [80, 88, 84, 86, 85], comp: 84, tag: 'WATCH' }, { n: 'Meghna Das', age: 15, sport: 'Kabaddi', region: 'W. Bengal', s: [78, 90, 82, 80, 89], comp: 83, tag: 'WATCH' }, ]; const SUBS = ['Vision', 'Reflex', 'Track', 'Decide', 'Coord']; function tagChip(tag) { const m = { ELITE: 'accent', RISING: 'cyan', WATCH: 'saffron' }; return {tag}; } function ScoreBars({ s }) { return (
{s.map((v, i) => (
= 88 ? 'var(--accent)' : v >= 80 ? 'var(--cyan)' : 'var(--saffron)', borderRadius: 1 }} /> ))}
); } function TalentScreen({ onNav }) { const [sport, setSport] = useState('ALL'); const sports = ['ALL', 'Cricket', 'Archery', 'Boxing', 'Shooting']; const rows = sport === 'ALL' ? PROSPECTS : PROSPECTS.filter(p => p.sport === sport); const maxF = FUNNEL[0].v; return (
━━ Khelo India · talent pipeline · FY 2026–27
Talent Identification
{/* KPI row */}
Athletes Screened · YTD
48,200
▲ +12,400 this quarter
High-Potential Flagged
247
Top 0.5% · AI-ranked
Khelo India Candidates
6,240
28 states · 13 sports
Avg Composite · Flagged
86.4
▲ vision-led profile
{/* Funnel + leaderboard */}
Identification Pipeline
0.5% CONVERSION · SCHOOL → NCoE
{FUNNEL.map((f, i) => (
{f.l}
{f.v.toLocaleString()}
))}
High-Potential Leaderboard
{sports.map(s => ( ))}
{rows.map((p, i) => ( onNav && onNav('scientist')}> ))}
RankAthleteAgeSportRegion V·Rf·Tr·Dc·CoCompositeBand
#{String(i + 1).padStart(2, '0')}
{p.n.split(' ').map(w => w[0]).join('')}
{p.n}
{p.age} {p.sport} {p.region} = 88 ? 'var(--accent)' : 'var(--fg-0)' }}>{p.comp} {tagChip(p.tag)}
{/* Right: spotlight + AI eval + filters */}
★ Rising Star
91 COMPOSITE
AR
Aditya Rane
15 · Cricket · Maharashtra
{[['Vision', 92], ['Reflex', 88], ['Tracking', 90], ['Decision', 85], ['Coordination', 87]].map(([l, v]) => (
{l} {v}
))}
AI Evaluation Basis
{[ { l: 'Vision', d: 'acuity, tracking, peripheral' }, { l: 'Reflexes', d: 'simple + choice reaction' }, { l: 'Tracking', d: 'multi-object, pursuit gain' }, { l: 'Decision Speed', d: 'anticipation, accuracy' }, { l: 'Coordination', d: 'eye-hand, eye-foot' }, ].map((r, i) => (
{r.l}
{r.d}
))}
Age-normalized against national bands. Ranks are decision-support only — final selection requires SAI panel confirmation.
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.talent = TalentScreen; // ---------- screens/medical.jsx ---------- // Medical & Rehab — baseline vs post-injury, concussion, return-to-play function DualLineChart({ baseline, current, height = 120 }) { const n = baseline.length; const all = [...baseline, ...current]; const max = Math.max(...all) * 1.1; const min = Math.min(...all) * 0.9; const range = max - min || 1; const w = 100; const norm = arr => arr.map((v, i) => `${(i / (n - 1)) * w},${100 - ((v - min) / range) * 100}`).join(' '); return ( {[25, 50, 75].map(y => )} ); } function ReadinessGauge({ pct, label, threshold = 85 }) { const R = 60, C = Math.PI * R; // half circle const clamped = Math.max(0, Math.min(100, pct)); const passed = pct >= threshold; return (
{/* Threshold tick */} {pct}
{label}
); } function MedicalScreen() { const baseline = [82, 84, 83, 85, 86, 84, 85, 87, 88, 86, 87, 88]; const current = [42, 48, 52, 55, 58, 62, 65, 68, 72, 74, 76, 78]; return (
━━ Confidential · Neuro-visual assessment
Rehabilitation · Athlete #SAI-BLR-1284
{/* Confidential notice */}
◆ CONFIDENTIAL Medical view. Access restricted to Dr. Sinha, Dr. Menon. Athlete + guardian consent on file. NayanTrack does not provide autonomous diagnosis.
{/* Injury timeline */}
Injury Timeline
DAY 42 POST-INJURY
{/* Line */}
{[ { at: 0, l: 'INJURY', d: 'Day 0', c: 'var(--red)' }, { at: 15, l: 'BASELINE ×', d: 'Day 3', c: 'var(--saffron)' }, { at: 33, l: '1st RETEST', d: 'Day 14', c: 'var(--cyan)' }, { at: 55, l: '2nd RETEST', d: 'Day 28', c: 'var(--cyan)' }, { at: 78, l: '3rd RETEST', d: 'Day 42', c: 'var(--accent)' }, { at: 100, l: 'RTP TARGET', d: 'Day 56', c: 'var(--fg-2)' }, ].map((e, i) => (
{e.l}
{e.d}
))}
{/* Row 1: Baseline vs current + Readiness */}
Attention Score · Baseline vs Recovery
Pre-injury baseline Post-injury recovery
Baseline avg
85.2
Current
78
Gap
−7.2
Recovery rate
+1.1/day
Return-to-Play Readiness
HOLD · 78%
{[ { l: 'Oculomotor', v: 88, ok: true }, { l: 'Attention', v: 82, ok: false }, { l: 'Reaction', v: 76, ok: false }, { l: 'Fixation', v: 85, ok: true }, ].map((r, i) => (
{r.ok ? '✓' : '△'} {r.l} {r.v}%
))}
{/* Row 2: Concussion screening + clinician notes */}
Oculomotor Battery · King-Devick / VOMS
42/60 PASS
{[ { t: 'Smooth Pursuit', b: '0.8°', c: '1.2°', d: '+0.4°', f: 'watch' }, { t: 'Saccade Latency', b: '210ms', c: '248ms', d: '+38ms', f: 'watch' }, { t: 'Convergence Near-Pt', b: '5cm', c: '9cm', d: '+4cm', f: 'flag' }, { t: 'VOR (Horizontal)', b: '1.0', c: '0.88', d: '−0.12', f: 'ok' }, { t: 'Visual Motion', b: '2/10', c: '4/10', d: '+2', f: 'ok' }, { t: 'Nystagmus', b: 'None', c: 'None', d: '—', f: 'ok' }, ].map((r, i) => ( ))}
TestBaselineCurrentΔFlag
{r.t} {r.b} {r.c} {r.d} {r.f === 'ok' ? OK : r.f === 'watch' ? WATCH : FLAG}
Clinician Notes & Rehab Plan
DR. SINHA · 15 JUL
Athlete presents with persistent convergence insufficiency and mildly delayed saccadic latency, consistent with post-concussion oculomotor pattern. Attention score trajectory is positive (+1.1/day over 4 weeks) and matches expected recovery for grade-2 concussion.
Recommend continuing convergence-focused rehab exercises and delaying return-to-play by 14 days. Retest scheduled for Day 56. No contact drills.
Prescribed exercises · this week
{[ 'Pencil push-ups · 3× daily · 10 reps', 'Brock string convergence · 2× daily', 'Saccadic training video · 15 min', 'Slow smooth-pursuit drill · 10 min', ].map((e, i) => (
{e}
))}
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.medical = MedicalScreen; // ---------- screens/centre.jsx ---------- // Centre Administrator — device fleet, calibration health, schedule function CentreScreen() { return (
━━ Bengaluru NCoE · Facility ops
Centre Administration
{/* KPI row */}
Athletes Enrolled
842
▲ +23 this month
Sessions · MTD
1,284
▲ 92% completion
Device Fleet
14units
12 online · 1 maint · 1 offline
Calibration Pass Rate
94.2%
▼ 2.1% vs last wk
{/* Device fleet + Today's schedule */}
Device Fleet
ALL 14 LAB FIELD WEAR VR
{[ { id: 'NT-LAB-01', t: 'Lab · Tobii Spectrum', l: 'Lab 1', q: 0.42, s: 128, lc: '2h ago', st: 'ok' }, { id: 'NT-LAB-02', t: 'Lab · Tobii Spectrum', l: 'Lab 1', q: 0.51, s: 96, lc: '4h ago', st: 'ok' }, { id: 'NT-LAB-03', t: 'Lab · SR EyeLink', l: 'Lab 2', q: 0.38, s: 142, lc: '1h ago', st: 'ok' }, { id: 'NT-FLD-04', t: 'Field · Portable', l: 'Field', q: 0.68, s: 84, lc: '8h ago', st: 'watch' }, { id: 'NT-FLD-05', t: 'Field · Portable', l: 'Field', q: 0.55, s: 71, lc: '6h ago', st: 'ok' }, { id: 'NT-WER-06', t: 'Wearable · Pupil Neon', l: 'Field', q: 0.72, s: 43, lc: '12h ago', st: 'watch' }, { id: 'NT-WER-07', t: 'Wearable · Pupil Neon', l: 'Field', q: '—', s: 0, lc: '3d ago', st: 'maint' }, { id: 'NT-VR-08', t: 'VR · Quest Pro', l: 'VR', q: 0.61, s: 32, lc: '1d ago', st: 'ok' }, { id: 'NT-VR-09', t: 'VR · Vive Focus', l: 'VR', q: '—', s: 0, lc: '—', st: 'offline' }, ].map(d => ( ))}
Device IDTypeLabCal. QualitySessionsLast CalStatus
{d.id} {d.t} {d.l} {typeof d.q === 'number' ? `${d.q.toFixed(2)}°` : '—'} {d.s} {d.lc} {d.st === 'ok' && ◆ ONLINE} {d.st === 'watch' && △ CAL DRIFT} {d.st === 'maint' && ⚙ MAINT} {d.st === 'offline' && ◯ OFFLINE}
Today · Bookings
14 / 18 SLOTS
{[ { t: '08:00', a: 'Batch 04 · Cricket U-19 (8)', d: 'LAB-01', c: 'M. Rao' }, { t: '09:30', a: 'M. Krishnan · Archery', d: 'LAB-03', c: 'K. Iyengar', highlight: true }, { t: '10:00', a: 'Talent-ID panel (14)', d: 'LAB-01,02,03', c: 'Regional' }, { t: '11:30', a: 'A. Prakash · Cricket', d: 'LAB-02', c: 'K. Iyengar' }, { t: '13:00', a: 'VR Session · Football (4)', d: 'VR-08', c: 'S. Rana' }, { t: '14:30', a: 'Rehab · A. Nair · Tennis', d: 'LAB-03', c: 'Dr. Sinha' }, { t: '16:00', a: 'Field · Hockey squad', d: 'FLD-04,05', c: 'B. Singh' }, { t: '17:30', a: 'Research · Elite panel', d: 'LAB-01', c: 'Dr. Menon' }, ].map((s, i) => (
{s.t}
{s.a}
{s.d} · {s.c}
))}
{/* Row 2: Utilization + Coach adoption */}
Lab Utilization · Last 14 days
08:00–20:00 · IST
{['LAB-01', 'LAB-02', 'LAB-03', 'FIELD', 'VR'].map((lab, li) => (
{lab}
{Array.from({ length: 14 }, (_, i) => { const v = Math.random(); const level = v > 0.7 ? 3 : v > 0.45 ? 2 : v > 0.2 ? 1 : 0; const colors = ['var(--bg-3)', 'oklch(0.92 0.19 115 / 0.3)', 'oklch(0.92 0.19 115 / 0.65)', 'var(--accent)']; return
; })}
{(60 + Math.random() * 30).toFixed(0)}%
))}
2 WEEKS AGO
LOW {[0, 0.3, 0.65, 1].map((o, i) => (
))} HIGH
TODAY
Coach Adoption
6 / 8 ACTIVE
{[ { n: 'K. Iyengar', s: 'Cricket', a: 34, ac: true }, { n: 'B. Singh', s: 'Hockey', a: 28, ac: true }, { n: 'M. Rao', s: 'Cricket', a: 26, ac: true }, { n: 'S. Rana', s: 'Football',a: 22, ac: true }, { n: 'Dr. Sinha', s: 'Medical', a: 18, ac: true }, { n: 'P. Verma', s: 'Boxing', a: 12, ac: true }, { n: 'R. Iyer', s: 'Tennis', a: 3, ac: false }, { n: 'A. Ghosh', s: 'Wrestling', a: 0,ac: false }, ].map((c, i) => (
{c.n.split(' ').map(w => w[0]).join('')}
{c.n}
{c.s}
{c.a}
SESS · MTD
))}
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.centre = CentreScreen; // ---------- screens/command.jsx ---------- // National Command — SAI admin: India map, centre-wise KPIs, alerts /* Approximate SAI NCoE / centre locations as % coords on a stylized India map bounding box */ const CENTRES = [ { id: 'DEL', name: 'Delhi', x: 40, y: 24, athletes: 1420, score: 76, trend: +2, sports: 11 }, { id: 'BLR', name: 'Bengaluru', x: 41, y: 70, athletes: 842, score: 82, trend: +5, sports: 9, highlight: true }, { id: 'PUN', name: 'Pune', x: 33, y: 60, athletes: 690, score: 79, trend: +3, sports: 8 }, { id: 'HYD', name: 'Hyderabad', x: 44, y: 63, athletes: 720, score: 74, trend: -1, sports: 7 }, { id: 'KOL', name: 'Kolkata', x: 68, y: 42, athletes: 810, score: 71, trend: +1, sports: 8 }, { id: 'GAN', name: 'Gandhinagar', x: 28, y: 45, athletes: 480, score: 73, trend: +2, sports: 6 }, { id: 'GUW', name: 'Guwahati', x: 74, y: 33, athletes: 340, score: 68, trend: -3, sports: 5, alert: true }, { id: 'CHN', name: 'Chennai', x: 44, y: 78, athletes: 620, score: 77, trend: +4, sports: 8 }, { id: 'BHO', name: 'Bhopal', x: 42, y: 46, athletes: 410, score: 70, trend: 0, sports: 6 }, { id: 'IMP', name: 'Imphal', x: 82, y: 38, athletes: 210, score: 65, trend: -2, sports: 4, alert: true }, { id: 'PAT', name: 'Patiala', x: 34, y: 20, athletes: 890, score: 80, trend: +3, sports: 10 }, { id: 'SON', name: 'Sonepat', x: 40, y: 22, athletes: 520, score: 74, trend: +1, sports: 6 }, { id: 'ALK', name: 'Aurangabad', x: 36, y: 56, athletes: 380, score: 72, trend: +2, sports: 5 }, { id: 'THI', name: 'Thiruvpm', x: 38, y: 88, athletes: 290, score: 76, trend: +1, sports: 5 }, ]; /* Simplified India silhouette path — enough to feel like India without heavy geo data */ const INDIA_PATH = ` M 30,10 L 45,8 L 55,10 L 65,15 L 75,20 L 82,25 L 88,32 L 85,40 L 78,42 L 72,44 L 68,50 L 68,58 L 64,64 L 60,70 L 56,76 L 52,82 L 46,88 L 40,92 L 36,88 L 33,80 L 30,72 L 28,64 L 26,56 L 24,48 L 26,40 L 30,32 L 32,24 L 30,16 Z `; function IndiaMap() { const [hovered, setHovered] = useState(null); return (
{/* Faint grid */} {/* India silhouette */} {/* Compass */} N {/* Centres */} {CENTRES.map(c => { const size = 0.6 + (c.athletes / 1500) * 2.4; const color = c.alert ? 'var(--red)' : c.highlight ? 'var(--accent)' : 'var(--cyan)'; return ( setHovered(c.id)} onMouseLeave={() => setHovered(null)} style={{ cursor: 'pointer' }}> {/* pulse for alerts */} {c.alert && ( )} {c.name.toUpperCase()} ); })} {/* Legend */}
NCoE / SAI CENTRE
ACTIVE
HIGH PERFORMANCE
ATTENTION REQUIRED
SIZE ∝ ATHLETES ENROLLED
{/* Attribution */}
SCHEMATIC · NOT TO SCALE
); } function SportBar({ label, value, max, color = 'var(--accent)' }) { return (
{label}
{value.toLocaleString()}
); } function CommandScreen() { return (
━━ Sports Authority of India · National view
National Command Dashboard
FY 2026–27 · Q2 SAI · CLASSIFIED
{/* Top KPI row */}
Athletes Enrolled · Nationwide
18,240
▲ +1,240 QoQ
Assessments · YTD
64,820
▲ 92% completion
Centres Online
24/ 26
2 in commissioning
High-Potential Athletes
247
Top 1.4% · AI-flagged
{/* Row 1: Map + right column stack */}
Centre Performance · India
ATTENTION ENROLLMENT CAL. HEALTH
{/* High-potential alerts */}
High-Potential Athlete Alerts
12 NEW
{[ { n: 'A. Prakash', sp: 'Cricket', c: 'BLR', pctl: 97, delta: '+8' }, { n: 'V. Kumar', sp: 'Shooting', c: 'PUN', pctl: 96, delta: '+6' }, { n: 'R. Deshmukh', sp: 'Kabaddi', c: 'GAN', pctl: 95, delta: '+9' }, { n: 'S. Mehta', sp: 'Archery', c: 'PAT', pctl: 94, delta: '+5' }, { n: 'K. Bora', sp: 'Boxing', c: 'GUW', pctl: 93, delta: '+7' }, ].map((a, i) => (
{a.n.split(' ').map(w => w[0]).join('')}
{a.n}
{a.sp} · {a.c}
{a.pctl}%ile
▲ {a.delta}
))}
{/* Data quality */}
Platform Health
◆ ALL SYSTEMS
Calibration Pass
93.4%
Data Quality
96.8%
Devices Online
218/240
Storage · Encrypted
4.2TB
{/* Row 2: Sport distribution + centre table */}
Sport-wise Distribution
13 SPORTS · 18,240 ATHLETES
{[ { s: 'Cricket', v: 4820, c: 'var(--accent)' }, { s: 'Hockey', v: 2140, c: 'var(--accent)' }, { s: 'Football', v: 1980, c: 'var(--accent)' }, { s: 'Badminton', v: 1620, c: 'var(--cyan)' }, { s: 'Shooting', v: 1240, c: 'var(--cyan)' }, { s: 'Archery', v: 1180, c: 'var(--cyan)' }, { s: 'Boxing', v: 980, c: 'var(--cyan)' }, { s: 'Kabaddi', v: 890, c: 'var(--saffron)' }, { s: 'Tennis', v: 780, c: 'var(--saffron)' }, { s: 'Wrestling', v: 720, c: 'var(--saffron)' }, { s: 'Table Tennis', v: 640, c: 'var(--saffron)' }, { s: 'Para Sports', v: 520, c: 'var(--purple)' }, { s: 'Esports', v: 210, c: 'var(--purple)' }, ].map(sp => ( ))}
Centre Leaderboard
SCORE ENROLLMENT ADOPTION
{CENTRES .slice() .sort((a, b) => b.score - a.score) .map((c, i) => ( ))}
RankCentreAthletesSportsAvg ScoreΔ QtrStatus
#{String(i + 1).padStart(2, '0')}
{c.name}
{c.athletes.toLocaleString()} {c.sports} = 78 ? 'var(--accent)' : 'var(--fg-0)' }}>{c.score} 0 ? 'var(--accent)' : c.trend < 0 ? 'var(--red)' : 'var(--fg-2)' }}> {c.trend > 0 ? '▲' : c.trend < 0 ? '▼' : '—'} {Math.abs(c.trend)} {c.alert ? ATTENTION : c.highlight ? FLAGSHIP : ACTIVE}
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.command = CommandScreen; // ---------- screens/lab.jsx ---------- // Test Designer — author sport stimuli, AOIs, scoring rules, normative bands const LAB_AOIS = [ { id: 'aoi-release', l: 'RELEASE POINT', x: 62, y: 20, w: 16, h: 20, weight: 1.0, color: 'var(--accent)' }, { id: 'aoi-bat', l: 'BAT / BODY', x: 30, y: 52, w: 22, h: 24, weight: 0.6, color: 'var(--cyan)' }, { id: 'aoi-pitch', l: 'PITCH LENGTH', x: 48, y: 66, w: 26, h: 16, weight: 0.4, color: 'var(--saffron)' }, ]; const SCORING_RULES = [ { m: 'Quiet-Eye Onset', op: '≥', v: '1.0 s', pts: 30 }, { m: 'First Fixation AOI', op: '=', v: 'RELEASE', pts: 25 }, { m: 'Response Accuracy', op: '≥', v: '80 %', pts: 25 }, { m: 'Blink in Window', op: '=', v: 'FALSE', pts: 20 }, ]; const NORM_BANDS = [ { l: 'Elite', lo: 88, hi: 100, c: 'var(--accent)' }, { l: 'High', lo: 76, hi: 88, c: 'var(--cyan)' }, { l: 'Developing', lo: 60, hi: 76, c: 'var(--saffron)' }, { l: 'Baseline', lo: 0, hi: 60, c: 'var(--red)' }, ]; function LabScene({ selected, onSelect }) { return (
{/* cricket scene hint */} {/* AOI editor rectangles */} {LAB_AOIS.map(a => { const sel = a.id === selected; return (
onSelect(a.id)} style={{ position: 'absolute', left: `${a.x}%`, top: `${a.y}%`, width: `${a.w}%`, height: `${a.h}%`, border: `${sel ? 2 : 1}px dashed ${a.color}`, background: sel ? 'oklch(0.92 0.19 115 / 0.06)' : 'transparent', cursor: 'pointer', }}>
{a.l}
{/* resize handles when selected */} {sel && ['nw','ne','sw','se'].map(h => (
))}
); })}
STIMULUS CANVAS · CRICKET · 1920×1080
CLICK AN AOI TO EDIT · DRAG HANDLES TO RESIZE
); } function LabScreen({ onNav }) { const [selected, setSelected] = useState('aoi-release'); const aoi = LAB_AOIS.find(a => a.id === selected) || LAB_AOIS[0]; return (
━━ Protocol authoring · draft v0.3
Test Designer
{/* meta bar */}
CRICKET ANTICIPATION U-19 Bowler Release · Anticipation Test · 12 trials · 8.0 s window 3 AOIs · 4 RULES
{/* Canvas + rules */}
{/* stimulus timeline */}
Stimulus Timeline · per trial
8.0 s
{[ { at: 5, w: 8, l: 'FIXATION CROSS', c: 'var(--fg-3)' }, { at: 18, w: 30, l: 'RUN-UP', c: 'var(--cyan)' }, { at: 48, w: 4, l: 'RELEASE', c: 'var(--accent)' }, { at: 60, w: 20, l: 'FLIGHT', c: 'var(--saffron)' }, { at: 82, w: 12, l: 'RESPONSE', c: 'var(--green)' }, ].map((b, i) => (
{b.w > 8 ? b.l : ''}
))}
{[0,2,4,6,8].map(t => {t.toFixed(1)}s)}
{/* scoring rules */}
Scoring Rules · 100 pts
{SCORING_RULES.map((r, i) => ( ))}
MetricConditionTargetPoints
{r.m} {r.op} {r.v} {r.pts}
{/* Inspector column */}
AOI Inspector
{aoi.l}
{[ ['Label', aoi.l], ['ID', aoi.id], ['Shape', 'Rectangle'], ['Position', `${aoi.x}% , ${aoi.y}%`], ['Size', `${aoi.w}% × ${aoi.h}%`], ].map(([k, v]) => (
{k} {v}
))}
Scoring Weight {aoi.weight.toFixed(1)}
{LAB_AOIS.map(a => ( ))}
Normative Bands
U-19 · NATIONAL
{/* stacked band bar */}
{NORM_BANDS.slice().reverse().map(b => (
))}
{NORM_BANDS.map(b => (
{b.l} {b.lo}–{b.hi}
))}
Component Palette
{['✚ AOI Rect', '◯ AOI Circle', '◆ Stimulus', '↕ Distractor', '⏱ Timer', '⌨ Response'].map(c => ( ))}
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.lab = LabScreen; // ---------- screens/reports.jsx ---------- // Reports & Export — build and export athlete/coach/tournament/medical reports const REPORT_TYPES = [ { id: 'athlete', t: 'Athlete Report', d: 'Individual vision + cognitive profile', icon: '◉' }, { id: 'coach', t: 'Coach Report', d: 'Squad trends + drill compliance', icon: '◈' }, { id: 'tournament', t: 'Tournament Report', d: 'Event-wide readiness + rankings', icon: '★' }, { id: 'medical', t: 'Medical Report', d: 'RTP status + oculomotor battery', icon: '✚' }, { id: 'vision', t: 'Vision Report', d: 'Sports-vision assessment summary', icon: '◎' }, ]; const RECENT = [ { t: 'M. Krishnan · Vision Report', by: 'Dr. Menon', when: '2h ago', fmt: 'PDF' }, { t: 'Bengaluru Squad · Weekly', by: 'K. Iyengar', when: '1d ago', fmt: 'PDF' }, { t: 'Khelo India · Talent Shortlist', by: 'SAI HQ', when: '2d ago', fmt: 'XLSX' }, { t: 'A. Prakash · RTP Clearance', by: 'Dr. Sinha', when: '3d ago', fmt: 'PDF' }, { t: 'Q2 Ministry Dashboard', by: 'SAI HQ', when: '5d ago', fmt: 'DASH' }, ]; function MiniRadar() { const vals = [78, 82, 74, 65, 88, 71, 80, 76]; const cx = 42, cy = 42, R = 34, N = vals.length; const pt = (i, r) => { const a = (i / N) * Math.PI * 2 - Math.PI / 2; return [cx + Math.cos(a) * r, cy + Math.sin(a) * r]; }; const poly = vals.map((v, i) => pt(i, (v / 100) * R).join(',')).join(' '); return ( {[0.5, 1].map(f => pt(i, R * f).join(',')).join(' ')} fill="none" stroke="var(--line)" strokeWidth="0.6" />)} ); } function ReportPreview({ type }) { const rt = REPORT_TYPES.find(r => r.id === type) || REPORT_TYPES[0]; return (
{/* doc header */}
NayanTrack नयन
Sports Authority of India · {rt.t}
REF · NT-RPT-2026-0472
15 JUL 2026 · CONFIDENTIAL
{/* subject */}
MK
Meera Krishnan
SAI-PUN-0472 · Archery · 21 F · Pune NCoE
Composite
84
{/* body grid */}
Composite Indicators
Key Metrics
{[['Quiet Eye', '1.24 s', 'up'], ['Reaction Time', '248 ms', 'up'], ['Aim Deviation', '0.42°', 'up'], ['Cognitive Load', 'Low', 'flat'], ['Percentile', '92nd', 'up']].map(([k, v, d]) => (
{k} {d === 'up' ? '▲ ' : ''}{v}
))}
{/* AI summary */}
◆ AI SUMMARY · COACH-REVIEWED
Exceptional aim-point stability (0.42°, 18% tighter than elite median) with an earlier quiet-eye onset than baseline. Watch: first-fixation latency and pre-release blink suppression. Recommended: blink-timing and target-acquisition drills.
NayanTrack · Not for autonomous diagnosis · SAI Confidential Page 1 / 6
); } function ReportsScreen() { const [type, setType] = useState('vision'); return (
━━ Reporting · export centre
Reports & Export
{/* Report types */}
Report Type
{REPORT_TYPES.map(r => ( ))}
Sections
{[['Cover + subject', true], ['Composite indicators', true], ['Key metrics', true], ['Heatmap + gaze', true], ['Benchmark vs elite', true], ['AI summary', true], ['Raw data appendix', false]].map(([l, on]) => (
{l}
))}
{/* Preview */} {/* Right: export + recent + scheduled */}
Export Format
{[ { l: 'PDF Document', d: 'Print-ready · 6 pages', icon: '⤓', primary: true }, { l: 'Excel Workbook', d: 'Raw metrics + pivots', icon: '⊞' }, { l: 'Interactive Dashboard', d: 'Shareable web link', icon: '◱' }, ].map(f => ( ))}
Recent Reports
32 THIS MONTH
{RECENT.map((r, i) => (
{r.t}
{r.by} · {r.when}
{r.fmt}
))}
◷ Scheduled
Weekly squad report auto-generates every Monday 07:00 IST and emails Coach Iyengar + Centre Admin.
); } if (!window.NT_SCREENS) window.NT_SCREENS = {}; window.NT_SCREENS.reports = ReportsScreen;