// ============ 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 (
{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
⤓ Export Shortlist
◆ Panel Review
↗ Nominate to NCoE
{/* 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 => (
setSport(s)}>{s.toUpperCase()}
))}
Rank Athlete Age Sport Region
V·Rf·Tr·Dc·Co Composite Band
{rows.map((p, i) => (
onNav && onNav('scientist')}>
#{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: '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) => (
))}
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
⤓ Clinical Report
Sign RTP Decision
{/* 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) => (
))}
{/* Row 1: Baseline vs current + Readiness */}
Attention Score · Baseline vs Recovery
Pre-injury baseline
Post-injury recovery
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
Test Baseline Current Δ Flag
{[
{ 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) => (
{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}
))}
Amend Plan
Add Note
Escalate
);
}
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
+ Book Slot
+ Enroll Athlete
↗ Weekly Ops Report
{/* 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
Device ID Type Lab Cal. Quality Sessions Last Cal Status
{[
{ 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 => (
{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) => (
))}
{/* 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('')}
))}
);
}
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
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
↗ Ministry Report
{/* 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('')}
))}
{/* Data quality */}
Platform Health
◆ ALL SYSTEMS
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
Rank Centre Athletes Sports Avg Score Δ Qtr Status
{CENTRES
.slice()
.sort((a, b) => b.score - a.score)
.map((c, i) => (
#{String(i + 1).padStart(2, '0')}
{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
◷ Preview
Save Draft
▲ Publish Protocol
{/* 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
+ Rule
Metric Condition Target Points
{SCORING_RULES.map((r, i) => (
{r.m}
{r.op}
{r.v}
{r.pts}
✎
))}
{/* Inspector column */}
{[
['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 => (
setSelected(a.id)}>{a.l.split(' ')[0]}
))}
Normative Bands
U-19 · NATIONAL
{/* stacked band bar */}
{NORM_BANDS.slice().reverse().map(b => (
))}
{NORM_BANDS.map(b => (
{b.l}
{b.lo}–{b.hi}
))}
{['✚ AOI Rect', '◯ AOI Circle', '◆ Stimulus', '↕ Distractor', '⏱ Timer', '⌨ Response'].map(c => (
{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
{/* body grid */}
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
⤓ Export XLSX
◱ Open Dashboard
⤓ Export PDF
{/* Report types */}
{REPORT_TYPES.map(r => (
setType(r.id)} style={{
width: '100%', textAlign: 'left', display: 'flex', gap: 12, alignItems: 'flex-start',
padding: '14px 16px', borderBottom: '1px solid var(--line)',
background: r.id === type ? 'var(--bg-2)' : 'transparent',
borderLeft: r.id === type ? '2px solid var(--accent)' : '2px solid transparent',
}}>
{r.icon}
))}
{[['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 */}
{[
{ 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 => (
{f.icon}
))}
Recent Reports
32 THIS MONTH
{RECENT.map((r, i) => (
))}
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;