tazwarrrr commited on
Commit
21c8704
·
1 Parent(s): 243b15a
Files changed (2) hide show
  1. frontend/src/App.jsx +972 -172
  2. frontend/tailwind.config.js +1 -0
frontend/src/App.jsx CHANGED
@@ -4,6 +4,26 @@ const API_BASE = window.location.protocol === 'file:'
4
  ? 'http://localhost:8000'
5
  : window.location.origin
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  // ─── Template Kernels ─────────────────────────────────────────────────────────
8
 
9
  const KERNEL_VECTOR_ADD = String.raw`
@@ -522,65 +542,683 @@ const AGENT_LABEL = {
522
  coordinator: 'COORDINATOR',
523
  }
524
 
525
- // Tailwind class strings per status — all literals so JIT can scan them
526
  const STATUS = {
527
  idle: {
528
- dot: 'bg-[#1E2D40]',
529
- badge: 'bg-[#1E2D40] text-[#6B7A99]',
530
  label: 'IDLE',
 
 
 
531
  },
532
  running: {
533
- dot: 'bg-[#FFB800] animate-rocm-pulse',
534
- badge: 'bg-[#1A1500] text-[#FFB800]',
535
  label: 'RUNNING',
 
 
 
536
  },
537
  done: {
538
- dot: 'bg-[#00FF88]',
539
- badge: 'bg-[#001A0D] text-[#00FF88]',
540
  label: 'DONE',
 
 
 
541
  },
542
  failed: {
543
- dot: 'bg-[#FF3B3B]',
544
- badge: 'bg-[#1A0000] text-[#FF3B3B]',
545
  label: 'FAILED',
 
 
 
546
  },
547
  }
548
 
549
  const INITIAL_AGENTS = Object.fromEntries(
550
- AGENT_LIST.map(a => [a, { status: 'idle', message: 'Waiting', detail: '' }])
551
  )
552
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
553
  // ─── AgentCard ────────────────────────────────────────────────────────────────
554
 
555
  function AgentCard({ name, state }) {
556
  const s = STATUS[state.status] ?? STATUS.idle
 
 
 
557
  return (
558
- <div className="rounded-lg border border-[#1E2D40] bg-[#111827] p-3">
559
- <div className="flex items-center gap-3">
560
- {/* Status dot */}
561
- <span className={`shrink-0 w-2 h-2 rounded-full ${s.dot}`} />
562
-
563
- {/* Agent info */}
564
- <div className="flex-1 min-w-0">
565
- <div className="font-code text-[11px] text-[#6B7A99] tracking-widest uppercase">
 
 
 
 
 
566
  {AGENT_LABEL[name]}
567
  </div>
568
- <div className="font-ui text-[13px] text-[#F0F4FF] mt-0.5 truncate">
569
- {state.message || 'Waiting…'}
 
 
570
  </div>
571
  </div>
572
-
573
- {/* Status badge */}
574
- <span
575
- className={`shrink-0 font-code text-[10px] font-semibold px-2 py-0.5 rounded tracking-wider ${s.badge}`}
576
- >
577
- {s.label}
578
- </span>
579
  </div>
580
-
581
- {/* Detail (collapsible — shown only when present) */}
582
  {state.detail && (
583
- <p className="mt-2 font-ui text-[11px] text-[#6B7A99] italic leading-relaxed line-clamp-3">
 
 
 
 
 
 
 
 
 
 
 
 
584
  {state.detail}
585
  </p>
586
  )}
@@ -601,10 +1239,17 @@ export default function App() {
601
 
602
  const timerRef = useRef(null)
603
  const startRef = useRef(null)
 
604
 
605
  const lineCount = code ? code.split('\n').length : 1
606
 
607
- // ── Timer ────────────────────────────────────────────────────────────────────
 
 
 
 
 
 
608
  const startTimer = () => {
609
  startRef.current = Date.now()
610
  timerRef.current = setInterval(
@@ -620,10 +1265,10 @@ export default function App() {
620
 
621
  useEffect(() => () => stopTimer(), [])
622
 
623
- // ── Helpers ───────────────────────────────────────────────────────────────────
624
  const resetAgents = () =>
625
  setAgents(Object.fromEntries(
626
- AGENT_LIST.map(a => [a, { status: 'idle', message: 'Waiting', detail: '' }])
627
  ))
628
 
629
  const updateAgent = (agent, patch) =>
@@ -636,19 +1281,19 @@ export default function App() {
636
 
637
  const fmtElapsed = (ms) => `${(ms / 1000).toFixed(1)}s`
638
 
639
- // ── Demo mode fallback ────────────────────────────────────────────────────────
640
  const runDemo = async () => {
641
  const steps = [
642
- { agent: 'analyzer', status: 'running', message: 'Scanning CUDA patterns', detail: '' },
643
  { agent: 'analyzer', status: 'done', message: 'Found 3 critical AMD issues', detail: 'warp-32 assumption in reduction tail, threadIdx%32 idiom, LDS bank conflict pattern' },
644
- { agent: 'translator', status: 'running', message: 'Running hipify + LLM pass', detail: '' },
645
  { agent: 'translator', status: 'done', message: 'Translation complete', detail: 'hipify applied; 7 additional LLM corrections for wavefront-64 semantics' },
646
- { agent: 'optimizer', status: 'running', message: 'Proposing optimizations', detail: '' },
647
  { agent: 'optimizer', status: 'done', message: '4 optimization patches generated', detail: 'LDS padding, wavefront-aware reduction, coalesced access pattern' },
648
- { agent: 'tester', status: 'running', message: 'Compiling with hipcc', detail: '' },
649
- { agent: 'tester', status: 'done', message: 'Compiled and profiled on gfx942', detail: 'rocprof: 0.026 ms correctness verified' },
650
- { agent: 'coordinator', status: 'running', message: 'Assembling final report', detail: '' },
651
- { agent: 'coordinator', status: 'done', message: 'Migration complete 2.61× speedup', detail: 'data_source: demo_artifact' },
652
  ]
653
 
654
  for (const step of steps) {
@@ -666,7 +1311,7 @@ export default function App() {
666
  setRunning(false)
667
  }
668
 
669
- // ── Main action ───────────────────────────────��───────────────────────────────
670
  const handlePort = async () => {
671
  if (running || !code.trim()) return
672
 
@@ -699,7 +1344,7 @@ export default function App() {
699
 
700
  buf += dec.decode(value, { stream: true })
701
  const lines = buf.split('\n')
702
- buf = lines.pop() // keep any incomplete trailing line
703
 
704
  for (const line of lines) {
705
  if (!line.startsWith('data: ')) continue
@@ -716,20 +1361,15 @@ export default function App() {
716
  detail: ev.detail ?? '',
717
  })
718
 
719
- // Extract benchmark data from the coordinator's done event
720
  if (ev.agent === 'coordinator' && ev.status === 'done') {
721
  let report = ev.result ?? null
722
  if (!report && ev.detail) {
723
- try {
724
- report = JSON.parse(ev.detail)
725
- } catch (_) {
726
- report = null
727
- }
728
  }
729
  const r = report ?? ev
730
  setBenchmark({
731
- total_changes: r.total_changes ?? r.changes_made ?? '',
732
- bugs_found: r.bugs_found ?? r.critical_bugs ?? r.static_risk_report?.critical_count ?? '',
733
  compiled_successfully: r.compiled_successfully ?? r.compiled ?? r.migration_success ?? false,
734
  data_source: r.data_source ?? 'unknown',
735
  })
@@ -738,147 +1378,307 @@ export default function App() {
738
  }
739
  }
740
  } catch {
741
- setErrorBanner('Backend unavailable running in demo mode')
742
  runDemo()
743
- return // runDemo handles stopTimer + setRunning(false)
744
  }
745
 
746
  stopTimer()
747
  setRunning(false)
748
  }
749
 
750
- // ── Render ────────────────────────────────────────────────────────────────────
751
- return (
752
- <div
753
- className="min-h-screen flex flex-col text-[#F0F4FF] font-ui"
754
- style={{ background: 'linear-gradient(180deg, #0A0E1A 0%, #0D1220 100%)' }}
755
- >
756
- {/* ── Error banner ──────────────────────────────────────────────────────── */}
757
- {errorBanner && (
758
- <div className="flex-none px-6 py-2.5 border-b border-[#FF3B3B] bg-[#1A0000] font-code text-[13px] text-[#FF3B3B]">
759
- ⚠ {errorBanner}
760
- </div>
761
- )}
762
-
763
- {/* ── Two-column main layout ────────────────────────────────────────────── */}
764
- <div className="flex flex-1 overflow-hidden">
765
 
766
- {/* ──── LEFT PANEL 58% ─────────────────────────────────────────────── */}
767
- <div className="w-[58%] flex flex-col p-5 gap-4 border-r border-[#1E2D40] overflow-y-auto">
 
 
 
768
 
769
- {/* Editor header */}
770
- <div className="flex justify-between items-center">
771
- <span className="font-code text-[12px] text-[#6B7A99]">// CUDA source</span>
772
- <span className="font-code text-[12px] text-[#6B7A99]">{lineCount} lines</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
773
  </div>
774
-
775
- {/* Code editor */}
776
- <textarea
777
- value={code}
778
- onChange={e => { setCode(e.target.value); setActiveTemplate(null) }}
779
- placeholder={'// Paste CUDA code here\n// or pick a demo below'}
780
- spellCheck={false}
781
- className={[
782
- 'w-full min-h-[300px] resize-y rounded-lg p-4',
783
- 'border border-[#1E2D40] bg-[#0D1525]',
784
- 'text-[#F0F4FF] font-code text-[13px] leading-[1.6]',
785
- 'focus:outline-none focus:border-[#00D4FF] transition-colors duration-150',
786
- '[tab-size:4] [caret-color:#00D4FF]',
787
- ].join(' ')}
788
- />
789
-
790
- {/* Template selector */}
791
- <div>
792
- <p className="font-ui text-[12px] text-[#6B7A99] mb-2.5">Select a template:</p>
793
- <div className="flex flex-wrap gap-2">
794
- {Object.keys(TEMPLATES).map(name => (
795
- <button
796
- key={name}
797
- onClick={() => selectTemplate(name)}
798
- className={[
799
- 'px-4 py-1.5 rounded-full border font-ui text-[13px]',
800
- 'cursor-pointer transition-colors duration-150',
801
- activeTemplate === name
802
- ? 'bg-[#001A24] border-[#00D4FF] text-[#00D4FF]'
803
- : 'bg-[#111827] border-[#1E2D40] text-[#F0F4FF] hover:border-[#00D4FF]',
804
- ].join(' ')}
805
- >
806
- {name}
807
- </button>
808
- ))}
809
- </div>
810
  </div>
811
-
812
- {/* PORT TO ROCM button */}
813
- <button
814
- onClick={handlePort}
815
- disabled={running || !code.trim()}
816
- className={[
817
- 'w-full h-12 rounded-lg font-code text-[14px] text-white font-semibold',
818
- '[letter-spacing:2px] transition-all duration-150',
819
- running || !code.trim()
820
- ? 'bg-[#FF3B3B] opacity-50 cursor-not-allowed'
821
- : 'bg-[#FF3B3B] hover:bg-[#FF1A1A] hover:shadow-[0_0_20px_rgba(255,59,59,0.35)] cursor-pointer',
822
- ].join(' ')}
823
- >
824
- {running ? 'RUNNING...' : 'PORT TO ROCM'}
825
- </button>
826
- </div>
827
-
828
- {/* ──── RIGHT PANEL 42% ────────────────────────────────────────────── */}
829
- <div className="w-[42%] flex flex-col p-5 gap-4 overflow-y-auto">
830
-
831
- {/* Pipeline header */}
832
- <div className="flex justify-between items-center">
833
- <span className="font-code text-[12px] text-[#6B7A99]">// Pipeline</span>
834
- <span className={`font-code text-[12px] transition-colors duration-300 ${running ? 'text-[#FFB800]' : 'text-[#6B7A99]'}`}>
835
  {fmtElapsed(elapsed)}
836
  </span>
 
 
 
 
 
 
 
 
 
837
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
838
 
839
- {/* Agent cards */}
840
- <div className="flex flex-col gap-2">
841
- {AGENT_LIST.map(agent => (
842
- <AgentCard key={agent} name={agent} state={agents[agent]} />
843
- ))}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
844
  </div>
845
- </div>
846
- </div>
847
 
848
- {/* ── Benchmark footer (hidden until run completes) ─────────────────────── */}
849
- {benchmark && (
850
- <div className="flex-none flex flex-wrap gap-6 px-6 py-4 border-t border-[#1E2D40] bg-[#0D1525]">
851
- {[
852
- { label: 'CHANGES MADE', value: benchmark.total_changes },
853
- { label: 'BUGS FOUND', value: benchmark.bugs_found },
854
- {
855
- label: 'COMPILE STATUS',
856
- value: benchmark.compiled_successfully ? 'SUCCESS' : 'FAILED',
857
- color: benchmark.compiled_successfully ? '#00FF88' : '#FF3B3B',
858
- },
859
- { label: 'DATA SOURCE', value: benchmark.data_source, isSource: true },
860
- ].map(({ label, value, color, isSource }) => (
861
- <div key={label} className="flex flex-col gap-1 min-w-[120px]">
862
- <span className="font-ui text-[10px] text-[#6B7A99] uppercase tracking-widest">
863
- {label}
864
- </span>
865
- <div className="flex items-center gap-2">
866
- <span
867
- className="font-code text-[18px] font-semibold"
868
- style={{ color: color ?? '#00D4FF' }}
869
- >
870
- {String(value ?? '—')}
871
  </span>
872
- {isSource && value === 'real_rocm' && (
873
- <span className="font-code text-[10px] text-[#00D4FF] border border-[#00D4FF] bg-[#001A24] px-2 py-0.5 rounded">
874
- LIVE HARDWARE
875
- </span>
876
- )}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
877
  </div>
878
  </div>
879
- ))}
 
880
  </div>
881
- )}
882
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
883
  )
884
  }
 
4
  ? 'http://localhost:8000'
5
  : window.location.origin
6
 
7
+ // ─── Global CSS ───────────────────────────────────────────────────────────────
8
+ const globalCSS = `
9
+ @import url('https://fonts.bunny.net/css?family=clash-display:400,500,600,700');
10
+ * { cursor: none !important; box-sizing: border-box; }
11
+ body { background: #080808; margin: 0; }
12
+ ::-webkit-scrollbar { width: 4px; height: 4px; }
13
+ ::-webkit-scrollbar-track { background: #080808; }
14
+ ::-webkit-scrollbar-thumb { background: #1a1a1a; border-radius: 2px; }
15
+ ::-webkit-scrollbar-thumb:hover { background: #b8ff57; }
16
+ .clash-display { font-family: 'Clash Display', sans-serif; }
17
+ @keyframes probe-blink { 0%,49%{opacity:1} 50%,100%{opacity:0} }
18
+ @keyframes badge-spin { to { transform: rotate(360deg) } }
19
+ @keyframes shine-sweep { from{background-position:200% 0} to{background-position:-200% 0} }
20
+ @keyframes slide-up { from{transform:translateY(100%);opacity:0} to{transform:translateY(0);opacity:1} }
21
+ @keyframes rocm-pulse { 0%,100%{opacity:1} 50%{opacity:0.2} }
22
+ @keyframes nav-dot-pulse { 0%,100%{opacity:1;box-shadow:0 0 6px #ff4d00} 50%{opacity:0.5;box-shadow:0 0 2px #ff4d00} }
23
+ @keyframes seg-glow { 0%,100%{box-shadow:4px 0 10px rgba(255,77,0,0.6)} 50%{box-shadow:4px 0 18px rgba(255,77,0,0.9)} }
24
+ .benchmark-footer { animation: slide-up 300ms ease forwards; }
25
+ `
26
+
27
  // ─── Template Kernels ─────────────────────────────────────────────────────────
28
 
29
  const KERNEL_VECTOR_ADD = String.raw`
 
542
  coordinator: 'COORDINATOR',
543
  }
544
 
 
545
  const STATUS = {
546
  idle: {
547
+ dot: '#1a1a1a',
 
548
  label: 'IDLE',
549
+ borderLeft: '2px solid #1a1a1a',
550
+ cardShadow: 'none',
551
+ badgeColor: null,
552
  },
553
  running: {
554
+ dot: '#ff4d00',
 
555
  label: 'RUNNING',
556
+ borderLeft: '2px solid #ff4d00',
557
+ cardShadow: '-4px 0 12px rgba(255,77,0,0.15)',
558
+ badgeColor: 'orange',
559
  },
560
  done: {
561
+ dot: '#b8ff57',
 
562
  label: 'DONE',
563
+ borderLeft: '2px solid #b8ff57',
564
+ cardShadow: 'none',
565
+ badgeColor: 'green',
566
  },
567
  failed: {
568
+ dot: '#ff3366',
 
569
  label: 'FAILED',
570
+ borderLeft: '2px solid #ff3366',
571
+ cardShadow: 'none',
572
+ badgeColor: 'coral',
573
  },
574
  }
575
 
576
  const INITIAL_AGENTS = Object.fromEntries(
577
+ AGENT_LIST.map(a => [a, { status: 'idle', message: 'Waiting\u2026', detail: '' }])
578
  )
579
 
580
+ // ─── Component 1: ROCmCursor ──────────────────────────────────────────────────
581
+
582
+ const BRACKET_STYLES = `
583
+ [data-bracket-state="default"] .bkt-corner { border-color: rgba(184,255,87,0.7); }
584
+ [data-bracket-state="default"] .bkt-tl { top:0; left:0; }
585
+ [data-bracket-state="default"] .bkt-tr { top:0; right:0; }
586
+ [data-bracket-state="default"] .bkt-bl { bottom:0; left:0; }
587
+ [data-bracket-state="default"] .bkt-br { bottom:0; right:0; }
588
+
589
+ [data-bracket-state="button"] .bkt-corner { border-color: rgba(255,77,0,1); }
590
+ [data-bracket-state="button"] .bkt-tl { top:6px; left:6px; }
591
+ [data-bracket-state="button"] .bkt-tr { top:6px; right:6px; }
592
+ [data-bracket-state="button"] .bkt-bl { bottom:6px; left:6px; }
593
+ [data-bracket-state="button"] .bkt-br { bottom:6px; right:6px; }
594
+
595
+ [data-bracket-state="input"] .bkt-corner { border-color: rgba(179,232,255,0.7); }
596
+ [data-bracket-state="input"] .bkt-tl { top:0; left:0; }
597
+ [data-bracket-state="input"] .bkt-tr { top:0; right:0; }
598
+ [data-bracket-state="input"] .bkt-bl { bottom:0; left:0; }
599
+ [data-bracket-state="input"] .bkt-br { bottom:0; right:0; }
600
+
601
+ [data-bracket-state="running"] .bkt-corner { border-color: rgba(255,77,0,0.9); }
602
+ [data-bracket-state="running"] .bkt-tl { top:0; left:0; }
603
+ [data-bracket-state="running"] .bkt-tr { top:0; right:0; }
604
+ [data-bracket-state="running"] .bkt-bl { bottom:0; left:0; }
605
+ [data-bracket-state="running"] .bkt-br { bottom:0; right:0; }
606
+
607
+ .bkt-corner {
608
+ position: absolute;
609
+ width: 8px;
610
+ height: 8px;
611
+ transition: top 180ms ease, left 180ms ease, right 180ms ease, bottom 180ms ease, border-color 150ms ease;
612
+ }
613
+ .bkt-tl { border-top: 1.5px solid; border-left: 1.5px solid; border-bottom: 1.5px solid transparent; border-right: 1.5px solid transparent; }
614
+ .bkt-tr { border-top: 1.5px solid; border-right: 1.5px solid; border-bottom: 1.5px solid transparent; border-left: 1.5px solid transparent; }
615
+ .bkt-bl { border-bottom: 1.5px solid; border-left: 1.5px solid; border-top: 1.5px solid transparent; border-right: 1.5px solid transparent; }
616
+ .bkt-br { border-bottom: 1.5px solid; border-right: 1.5px solid; border-top: 1.5px solid transparent; border-left: 1.5px solid transparent; }
617
+ `
618
+
619
+ function ROCmCursor({ running }) {
620
+ const dotRef = useRef(null)
621
+ const boxRef = useRef(null)
622
+ const mouseRef = useRef({ x: -200, y: -200 })
623
+ const lerpRef = useRef({ x: -200, y: -200 })
624
+ const rafRef = useRef(null)
625
+ const targetTypeRef = useRef('default')
626
+ const runningRef = useRef(running)
627
+
628
+ useEffect(() => { runningRef.current = running }, [running])
629
+
630
+ useEffect(() => {
631
+ const onMove = (e) => {
632
+ mouseRef.current = { x: e.clientX, y: e.clientY }
633
+ if (dotRef.current) {
634
+ dotRef.current.style.left = (e.clientX - 4) + 'px'
635
+ dotRef.current.style.top = (e.clientY - 9) + 'px'
636
+ }
637
+ }
638
+
639
+ const onOver = (e) => {
640
+ const el = e.target
641
+ if (el.closest('button, [role=button]')) {
642
+ targetTypeRef.current = 'button'
643
+ } else if (el.closest('textarea, input')) {
644
+ targetTypeRef.current = 'input'
645
+ } else {
646
+ targetTypeRef.current = 'default'
647
+ }
648
+ }
649
+
650
+ window.addEventListener('mousemove', onMove)
651
+ window.addEventListener('mouseover', onOver)
652
+
653
+ const loop = () => {
654
+ const lx = lerpRef.current.x + (mouseRef.current.x - lerpRef.current.x) * 0.10
655
+ const ly = lerpRef.current.y + (mouseRef.current.y - lerpRef.current.y) * 0.10
656
+ lerpRef.current = { x: lx, y: ly }
657
+
658
+ if (boxRef.current) {
659
+ boxRef.current.style.left = (lx - 18) + 'px'
660
+ boxRef.current.style.top = (ly - 18) + 'px'
661
+ const state = runningRef.current ? 'running' : targetTypeRef.current
662
+ boxRef.current.setAttribute('data-bracket-state', state)
663
+ }
664
+
665
+ rafRef.current = requestAnimationFrame(loop)
666
+ }
667
+ rafRef.current = requestAnimationFrame(loop)
668
+
669
+ return () => {
670
+ window.removeEventListener('mousemove', onMove)
671
+ window.removeEventListener('mouseover', onOver)
672
+ cancelAnimationFrame(rafRef.current)
673
+ }
674
+ }, [running])
675
+
676
+ const blinkDuration = running ? '0.5s' : '1s'
677
+ const dotColor = running ? '#ff4d00' : '#b8ff57'
678
+
679
+ return (
680
+ <>
681
+ <style dangerouslySetInnerHTML={{ __html: BRACKET_STYLES }} />
682
+ <span
683
+ ref={dotRef}
684
+ style={{
685
+ position: 'fixed',
686
+ zIndex: 9999,
687
+ pointerEvents: 'none',
688
+ fontFamily: '"JetBrains Mono", monospace',
689
+ fontSize: '12px',
690
+ color: dotColor,
691
+ lineHeight: 1,
692
+ userSelect: 'none',
693
+ animation: `probe-blink ${blinkDuration} step-end infinite`,
694
+ }}
695
+ >
696
+ &#9611;
697
+ </span>
698
+ <div
699
+ ref={boxRef}
700
+ data-bracket-state="default"
701
+ style={{
702
+ position: 'fixed',
703
+ width: '36px',
704
+ height: '36px',
705
+ zIndex: 9998,
706
+ pointerEvents: 'none',
707
+ }}
708
+ >
709
+ <div className="bkt-corner bkt-tl" />
710
+ <div className="bkt-corner bkt-tr" />
711
+ <div className="bkt-corner bkt-bl" />
712
+ <div className="bkt-corner bkt-br" />
713
+ </div>
714
+ </>
715
+ )
716
+ }
717
+
718
+ // ─── Component 2: AetherFlowHero ─────────────────────────────────────────────
719
+
720
+ function AetherFlowHero({ running, mousePos }) {
721
+ const canvasRef = useRef(null)
722
+ const particlesRef = useRef([])
723
+ const rafRef = useRef(null)
724
+ const runningRef = useRef(running)
725
+
726
+ useEffect(() => {
727
+ runningRef.current = running
728
+ }, [running])
729
+
730
+ useEffect(() => {
731
+ const canvas = canvasRef.current
732
+ if (!canvas) return
733
+ const ctx = canvas.getContext('2d')
734
+
735
+ const COLORS = [
736
+ '#b8ff57', '#b8ff57', '#b8ff57', '#b8ff57',
737
+ '#ff4d00', '#ff4d00',
738
+ '#b3e8ff', '#b3e8ff',
739
+ '#ff3366',
740
+ '#ffd60a',
741
+ ]
742
+
743
+ const resize = () => {
744
+ canvas.width = window.innerWidth
745
+ canvas.height = window.innerHeight
746
+ }
747
+ resize()
748
+
749
+ const initParticles = () => {
750
+ particlesRef.current = Array.from({ length: 80 }, () => ({
751
+ x: Math.random() * canvas.width,
752
+ y: Math.random() * canvas.height,
753
+ vx: (Math.random() - 0.5) * 0.6,
754
+ vy: (Math.random() - 0.5) * 0.6,
755
+ radius: 1 + Math.random(),
756
+ opacity: 0.3 + Math.random() * 0.5,
757
+ color: COLORS[Math.floor(Math.random() * COLORS.length)],
758
+ }))
759
+ }
760
+ initParticles()
761
+
762
+ let debounceTimer = null
763
+ const onResize = () => {
764
+ clearTimeout(debounceTimer)
765
+ debounceTimer = setTimeout(() => { resize(); initParticles() }, 100)
766
+ }
767
+ window.addEventListener('resize', onResize)
768
+
769
+ const draw = () => {
770
+ ctx.clearRect(0, 0, canvas.width, canvas.height)
771
+ const ps = particlesRef.current
772
+ const isRunning = runningRef.current
773
+ const mx = mousePos && mousePos.current ? mousePos.current.x : -999
774
+ const my = mousePos && mousePos.current ? mousePos.current.y : -999
775
+ const speedMult = isRunning ? 2.5 : 1
776
+ const opacityBonus = isRunning ? 0.2 : 0
777
+ const connMult = isRunning ? 3 : 1
778
+
779
+ for (const p of ps) {
780
+ const pdx = p.x - mx
781
+ const pdy = p.y - my
782
+ const dist = Math.sqrt(pdx * pdx + pdy * pdy)
783
+ if (dist < 100 && dist > 0) {
784
+ const force = Math.min(1.5, 80 / dist)
785
+ p.vx += (pdx / dist) * force * 0.04
786
+ p.vy += (pdy / dist) * force * 0.04
787
+ }
788
+
789
+ const maxSpeed = 0.3 * speedMult
790
+ const spd = Math.sqrt(p.vx * p.vx + p.vy * p.vy)
791
+ if (spd > maxSpeed) {
792
+ p.vx = (p.vx / spd) * maxSpeed
793
+ p.vy = (p.vy / spd) * maxSpeed
794
+ }
795
+
796
+ p.x += p.vx * speedMult
797
+ p.y += p.vy * speedMult
798
+
799
+ if (p.x < 0) p.x += canvas.width
800
+ if (p.x > canvas.width) p.x -= canvas.width
801
+ if (p.y < 0) p.y += canvas.height
802
+ if (p.y > canvas.height) p.y -= canvas.height
803
+
804
+ const op = Math.min(1, p.opacity + opacityBonus)
805
+ const hexOp = Math.round(op * 255).toString(16).padStart(2, '0')
806
+ ctx.beginPath()
807
+ ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2)
808
+ ctx.fillStyle = p.color + hexOp
809
+ ctx.fill()
810
+ }
811
+
812
+ for (let i = 0; i < ps.length; i++) {
813
+ for (let j = i + 1; j < ps.length; j++) {
814
+ const cdx = ps[i].x - ps[j].x
815
+ const cdy = ps[i].y - ps[j].y
816
+ const d = Math.sqrt(cdx * cdx + cdy * cdy)
817
+ if (d < 120) {
818
+ const alpha = (1 - d / 120) * 0.15 * connMult
819
+ ctx.beginPath()
820
+ ctx.moveTo(ps[i].x, ps[i].y)
821
+ ctx.lineTo(ps[j].x, ps[j].y)
822
+ ctx.strokeStyle = `rgba(184,255,87,${Math.min(1, alpha)})`
823
+ ctx.lineWidth = 0.5
824
+ ctx.stroke()
825
+ }
826
+ }
827
+ }
828
+
829
+ rafRef.current = requestAnimationFrame(draw)
830
+ }
831
+ rafRef.current = requestAnimationFrame(draw)
832
+
833
+ return () => {
834
+ cancelAnimationFrame(rafRef.current)
835
+ window.removeEventListener('resize', onResize)
836
+ clearTimeout(debounceTimer)
837
+ }
838
+ }, [])
839
+
840
+ return (
841
+ <canvas
842
+ ref={canvasRef}
843
+ style={{
844
+ position: 'fixed',
845
+ inset: 0,
846
+ zIndex: -1,
847
+ pointerEvents: 'none',
848
+ width: '100vw',
849
+ height: '100vh',
850
+ }}
851
+ />
852
+ )
853
+ }
854
+
855
+ // ─── Component 3: AnimatedShinyText ──────────────────────────────────────────
856
+
857
+ function AnimatedShinyText({ children, className }) {
858
+ return (
859
+ <span style={{ position: 'relative', display: 'inline-block' }} className={className}>
860
+ {children}
861
+ <span
862
+ style={{
863
+ position: 'absolute',
864
+ inset: 0,
865
+ background: 'linear-gradient(105deg, transparent 40%, rgba(255,255,255,0.18) 50%, transparent 60%)',
866
+ backgroundSize: '200% 100%',
867
+ animation: 'shine-sweep 2.4s linear infinite',
868
+ pointerEvents: 'none',
869
+ borderRadius: 'inherit',
870
+ }}
871
+ />
872
+ </span>
873
+ )
874
+ }
875
+
876
+ // ─── Component 4: HeroBadge ───────────────────────────────────────────────────
877
+
878
+ const BADGE_COLOR_MAP = {
879
+ green: '#b8ff57',
880
+ gold: '#ffd60a',
881
+ orange: '#ff4d00',
882
+ coral: '#ff3366',
883
+ blue: '#b3e8ff',
884
+ }
885
+
886
+ function HeroBadge({ children, color }) {
887
+ const c = BADGE_COLOR_MAP[color] || '#b8ff57'
888
+ return (
889
+ <span style={{ position: 'relative', display: 'inline-flex', alignItems: 'center', padding: '1px', borderRadius: '3px', overflow: 'hidden', flexShrink: 0 }}>
890
+ <span style={{
891
+ position: 'absolute',
892
+ inset: '-50%',
893
+ width: '200%',
894
+ height: '200%',
895
+ background: `conic-gradient(from 0deg, transparent 0%, ${c} 20%, transparent 40%)`,
896
+ animation: 'badge-spin 3s linear infinite',
897
+ zIndex: 0,
898
+ }} />
899
+ <span style={{
900
+ position: 'relative',
901
+ zIndex: 1,
902
+ background: '#0f0f0f',
903
+ borderRadius: '2px',
904
+ padding: '2px 8px',
905
+ fontFamily: '"JetBrains Mono", monospace',
906
+ fontSize: '10px',
907
+ color: c,
908
+ whiteSpace: 'nowrap',
909
+ }}>
910
+ {children}
911
+ </span>
912
+ </span>
913
+ )
914
+ }
915
+
916
+ // ─── Component 5: ModernAnimatedHero ─────────────────────────────────────────
917
+
918
+ const HERO_WORDS = ['cudaMalloc', 'hipMalloc', '__global__', 'wavefront64', 'gfx942', 'rocprof', 'HIP', 'ROCm', 'LDS', 'vsmem', 'tid', 'blockDim', 'threadIdx', '__syncthreads', '0xFF', '0x3F', '\u223f', '\u2295', '\u2593', '\u2591']
919
+ const SCRAMBLE_POOL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\u223f\u2295\u2593\u2591'
920
+ const HERO_TARGET_STR = 'CUDA \u2192 ROCm / MI300X'
921
+
922
+ function ModernAnimatedHero() {
923
+ const canvasRef = useRef(null)
924
+ const rafRef = useRef(null)
925
+ const [displayChars, setDisplayChars] = useState(
926
+ () => HERO_TARGET_STR.split('').map(c => ({ char: c, scrambling: false }))
927
+ )
928
+
929
+ useEffect(() => {
930
+ const canvas = canvasRef.current
931
+ if (!canvas) return
932
+ const ctx = canvas.getContext('2d')
933
+
934
+ const setSize = () => {
935
+ canvas.width = canvas.offsetWidth || window.innerWidth
936
+ canvas.height = 56
937
+ }
938
+ setSize()
939
+
940
+ const NUM_COLS = 20
941
+ const cols = Array.from({ length: NUM_COLS }, (_, i) => ({
942
+ x: (canvas.width / NUM_COLS) * i + (canvas.width / NUM_COLS / 2),
943
+ y: Math.random() * 56,
944
+ speed: 0.4 + Math.random() * 0.8,
945
+ wordIdx: Math.floor(Math.random() * HERO_WORDS.length),
946
+ }))
947
+
948
+ const draw = () => {
949
+ ctx.clearRect(0, 0, canvas.width, canvas.height)
950
+ ctx.font = '9px "JetBrains Mono", monospace'
951
+ for (const col of cols) {
952
+ const word = HERO_WORDS[col.wordIdx % HERO_WORDS.length]
953
+ ctx.fillStyle = 'rgba(184,255,87,0.25)'
954
+ ctx.fillText(word[0], col.x, col.y)
955
+ col.y += col.speed
956
+ if (col.y > 70) {
957
+ col.y = -10
958
+ col.wordIdx = (col.wordIdx + 1) % HERO_WORDS.length
959
+ }
960
+ }
961
+ rafRef.current = requestAnimationFrame(draw)
962
+ }
963
+ rafRef.current = requestAnimationFrame(draw)
964
+ return () => cancelAnimationFrame(rafRef.current)
965
+ }, [])
966
+
967
+ const scrambleAll = () => {
968
+ const target = HERO_TARGET_STR.split('')
969
+ target.forEach((finalChar, i) => {
970
+ const delay = i * 30
971
+ const duration = 600
972
+ setTimeout(() => {
973
+ const start = Date.now()
974
+ const tick = setInterval(() => {
975
+ const elapsed = Date.now() - start
976
+ if (elapsed >= duration) {
977
+ clearInterval(tick)
978
+ setDisplayChars(prev => {
979
+ const next = [...prev]
980
+ next[i] = { char: finalChar, scrambling: false }
981
+ return next
982
+ })
983
+ } else {
984
+ setDisplayChars(prev => {
985
+ const next = [...prev]
986
+ next[i] = { char: SCRAMBLE_POOL[Math.floor(Math.random() * SCRAMBLE_POOL.length)], scrambling: true }
987
+ return next
988
+ })
989
+ }
990
+ }, 40)
991
+ }, delay)
992
+ })
993
+ }
994
+
995
+ useEffect(() => {
996
+ scrambleAll()
997
+ const id = setInterval(scrambleAll, 8000)
998
+ return () => clearInterval(id)
999
+ }, [])
1000
+
1001
+ return (
1002
+ <div style={{ position: 'relative', height: '56px', width: '100%', overflow: 'hidden', background: '#080808', borderBottom: '1px solid #1a1a1a', flexShrink: 0 }}>
1003
+ <canvas ref={canvasRef} style={{ position: 'absolute', inset: 0, width: '100%', height: '56px' }} />
1004
+ <div style={{
1005
+ position: 'absolute', inset: 0,
1006
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
1007
+ pointerEvents: 'none',
1008
+ fontFamily: '"JetBrains Mono", monospace',
1009
+ fontSize: '13px',
1010
+ fontWeight: 600,
1011
+ letterSpacing: '2px',
1012
+ }}>
1013
+ {displayChars.map((c, i) => (
1014
+ <span key={i} style={{ color: c.scrambling ? '#555555' : '#b8ff57' }}>{c.char}</span>
1015
+ ))}
1016
+ </div>
1017
+ </div>
1018
+ )
1019
+ }
1020
+
1021
+ // ─── Component 6: HeroDitheringCard ──────────────────────────────────────────
1022
+
1023
+ const BAYER_4X4 = [[0, 8, 2, 10], [12, 4, 14, 6], [3, 11, 1, 9], [15, 7, 13, 5]]
1024
+
1025
+ function HeroDitheringCard({ children, style: extraStyle }) {
1026
+ const canvasRef = useRef(null)
1027
+ const drawnRef = useRef(false)
1028
+
1029
+ useEffect(() => {
1030
+ const canvas = canvasRef.current
1031
+ if (!canvas || drawnRef.current) return
1032
+ const w = Math.max(canvas.offsetWidth, 200)
1033
+ const h = Math.max(canvas.offsetHeight, 80)
1034
+ canvas.width = w
1035
+ canvas.height = h
1036
+ drawnRef.current = true
1037
+ const ctx = canvas.getContext('2d')
1038
+ const img = ctx.createImageData(w, h)
1039
+ for (let y = 0; y < h; y++) {
1040
+ for (let x = 0; x < w; x++) {
1041
+ const threshold = BAYER_4X4[y % 4][x % 4] / 16
1042
+ const idx = (y * w + x) * 4
1043
+ if (threshold > 0.5) {
1044
+ img.data[idx] = 184; img.data[idx + 1] = 255; img.data[idx + 2] = 87; img.data[idx + 3] = 255
1045
+ } else {
1046
+ img.data[idx] = 8; img.data[idx + 1] = 8; img.data[idx + 2] = 8; img.data[idx + 3] = 255
1047
+ }
1048
+ }
1049
+ }
1050
+ ctx.putImageData(img, 0, 0)
1051
+ }, [])
1052
+
1053
+ return (
1054
+ <div style={{ position: 'relative', overflow: 'hidden', borderRadius: '2px', ...extraStyle }}>
1055
+ <canvas
1056
+ ref={canvasRef}
1057
+ style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', zIndex: 0, opacity: 0.06, pointerEvents: 'none' }}
1058
+ />
1059
+ <div style={{ position: 'relative', zIndex: 1 }}>
1060
+ {children}
1061
+ </div>
1062
+ </div>
1063
+ )
1064
+ }
1065
+
1066
+ // ─── Component 7: WrapShader ──────────────────────────────────────────────────
1067
+
1068
+ let _wrapId = 0
1069
+
1070
+ function WrapShader({ children, active }) {
1071
+ const idRef = useRef(null)
1072
+ if (!idRef.current) idRef.current = `rocm-wrap-${++_wrapId}`
1073
+ const dispMapRef = useRef(null)
1074
+ const rafRef = useRef(null)
1075
+ const startRef = useRef(null)
1076
+ const activeRef = useRef(active)
1077
+
1078
+ useEffect(() => { activeRef.current = active }, [active])
1079
+
1080
+ useEffect(() => {
1081
+ if (!active) {
1082
+ cancelAnimationFrame(rafRef.current)
1083
+ if (dispMapRef.current) dispMapRef.current.setAttribute('scale', '3')
1084
+ return
1085
+ }
1086
+ startRef.current = performance.now()
1087
+ const animate = (now) => {
1088
+ if (!activeRef.current) {
1089
+ if (dispMapRef.current) dispMapRef.current.setAttribute('scale', '3')
1090
+ return
1091
+ }
1092
+ const t = ((now - startRef.current) % 2000) / 2000
1093
+ const scale = 3 + Math.sin(t * Math.PI * 2) * 3
1094
+ if (dispMapRef.current) dispMapRef.current.setAttribute('scale', String(scale.toFixed(2)))
1095
+ rafRef.current = requestAnimationFrame(animate)
1096
+ }
1097
+ rafRef.current = requestAnimationFrame(animate)
1098
+ return () => cancelAnimationFrame(rafRef.current)
1099
+ }, [active])
1100
+
1101
+ const filterId = idRef.current
1102
+
1103
+ return (
1104
+ <div style={{ position: 'relative', width: '42%', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
1105
+ <svg style={{ position: 'absolute', width: 0, height: 0, overflow: 'visible' }} aria-hidden="true">
1106
+ <defs>
1107
+ <filter id={filterId}>
1108
+ <feTurbulence type="fractalNoise" baseFrequency="0.015 0.015" numOctaves="2" seed="8" result="noise" />
1109
+ <feDisplacementMap ref={dispMapRef} in="SourceGraphic" in2="noise" scale="3" xChannelSelector="R" yChannelSelector="G" />
1110
+ </filter>
1111
+ </defs>
1112
+ </svg>
1113
+ <div style={{ filter: `url(#${filterId})`, flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
1114
+ {children}
1115
+ </div>
1116
+ </div>
1117
+ )
1118
+ }
1119
+
1120
+ // ─── MagneticButton ───────────────────────────────────────────────────────────
1121
+
1122
+ function MagneticButton({ children, onClick, disabled }) {
1123
+ const btnRef = useRef(null)
1124
+ const [transform, setTransform] = useState('translate(0px,0px)')
1125
+ const [isHover, setIsHover] = useState(false)
1126
+
1127
+ const onMouseMove = (e) => {
1128
+ if (disabled) return
1129
+ const rect = btnRef.current.getBoundingClientRect()
1130
+ const cx = rect.left + rect.width / 2
1131
+ const cy = rect.top + rect.height / 2
1132
+ const dx = Math.max(-10, Math.min(10, (e.clientX - cx) * 0.35))
1133
+ const dy = Math.max(-10, Math.min(10, (e.clientY - cy) * 0.35))
1134
+ setTransform(`translate(${dx}px,${dy}px)`)
1135
+ }
1136
+
1137
+ const onMouseLeave = () => {
1138
+ setTransform('translate(0px,0px)')
1139
+ setIsHover(false)
1140
+ }
1141
+
1142
+ const onMouseEnter = () => { if (!disabled) setIsHover(true) }
1143
+
1144
+ return (
1145
+ <button
1146
+ ref={btnRef}
1147
+ onClick={onClick}
1148
+ disabled={disabled}
1149
+ onMouseMove={onMouseMove}
1150
+ onMouseLeave={onMouseLeave}
1151
+ onMouseEnter={onMouseEnter}
1152
+ style={{
1153
+ width: '100%',
1154
+ height: '52px',
1155
+ background: disabled ? '#1a1a1a' : (isHover ? '#ff3300' : '#ff4d00'),
1156
+ color: disabled ? '#333333' : '#ffffff',
1157
+ border: 'none',
1158
+ borderRadius: '3px',
1159
+ cursor: disabled ? 'not-allowed' : 'pointer',
1160
+ transform: disabled ? 'translate(0px,0px)' : transform,
1161
+ transition: isHover
1162
+ ? 'transform 100ms linear, box-shadow 150ms, background 150ms'
1163
+ : 'transform 400ms cubic-bezier(0.34,1.56,0.64,1), box-shadow 150ms, background 150ms',
1164
+ boxShadow: !disabled && isHover ? '0 0 32px rgba(255,77,0,0.45)' : 'none',
1165
+ display: 'flex',
1166
+ alignItems: 'center',
1167
+ justifyContent: 'center',
1168
+ }}
1169
+ >
1170
+ {children}
1171
+ </button>
1172
+ )
1173
+ }
1174
+
1175
  // ─── AgentCard ────────────────────────────────────────────────────────────────
1176
 
1177
  function AgentCard({ name, state }) {
1178
  const s = STATUS[state.status] ?? STATUS.idle
1179
+ const isRunning = state.status === 'running'
1180
+ const isDoneCoord = state.status === 'done' && name === 'coordinator'
1181
+
1182
  return (
1183
+ <div style={{ background: 'transparent', padding: '12px' }}>
1184
+ <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
1185
+ <span style={{
1186
+ flexShrink: 0,
1187
+ width: '8px',
1188
+ height: '8px',
1189
+ borderRadius: '50%',
1190
+ background: s.dot,
1191
+ display: 'inline-block',
1192
+ animation: isRunning ? 'rocm-pulse 1.1s ease-in-out infinite' : 'none',
1193
+ }} />
1194
+ <div style={{ flex: 1, minWidth: 0 }}>
1195
+ <div style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: '10px', color: '#555555', letterSpacing: '0.15em', textTransform: 'uppercase' }}>
1196
  {AGENT_LABEL[name]}
1197
  </div>
1198
+ <div style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: '13px', color: '#e8e8e8', marginTop: '2px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
1199
+ {isDoneCoord
1200
+ ? <AnimatedShinyText><span style={{ color: '#b8ff57' }}>{state.message || 'Waiting\u2026'}</span></AnimatedShinyText>
1201
+ : (state.message || 'Waiting\u2026')}
1202
  </div>
1203
  </div>
1204
+ {s.badgeColor && (
1205
+ <HeroBadge color={s.badgeColor}>{s.label}</HeroBadge>
1206
+ )}
 
 
 
 
1207
  </div>
 
 
1208
  {state.detail && (
1209
+ <p style={{
1210
+ marginTop: '8px',
1211
+ fontFamily: '"JetBrains Mono", monospace',
1212
+ fontSize: '11px',
1213
+ color: '#555555',
1214
+ fontStyle: 'italic',
1215
+ lineHeight: '1.5',
1216
+ display: '-webkit-box',
1217
+ WebkitLineClamp: 3,
1218
+ WebkitBoxOrient: 'vertical',
1219
+ overflow: 'hidden',
1220
+ margin: '8px 0 0 0',
1221
+ }}>
1222
  {state.detail}
1223
  </p>
1224
  )}
 
1239
 
1240
  const timerRef = useRef(null)
1241
  const startRef = useRef(null)
1242
+ const mousePos = useRef({ x: -999, y: -999 })
1243
 
1244
  const lineCount = code ? code.split('\n').length : 1
1245
 
1246
+ useEffect(() => {
1247
+ const onMove = (e) => { mousePos.current = { x: e.clientX, y: e.clientY } }
1248
+ window.addEventListener('mousemove', onMove)
1249
+ return () => window.removeEventListener('mousemove', onMove)
1250
+ }, [])
1251
+
1252
+ // ── Timer ─────────────────────────────────────────────────────────────────
1253
  const startTimer = () => {
1254
  startRef.current = Date.now()
1255
  timerRef.current = setInterval(
 
1265
 
1266
  useEffect(() => () => stopTimer(), [])
1267
 
1268
+ // ── Helpers ───────────────────────────────────────────────────────────────
1269
  const resetAgents = () =>
1270
  setAgents(Object.fromEntries(
1271
+ AGENT_LIST.map(a => [a, { status: 'idle', message: 'Waiting\u2026', detail: '' }])
1272
  ))
1273
 
1274
  const updateAgent = (agent, patch) =>
 
1281
 
1282
  const fmtElapsed = (ms) => `${(ms / 1000).toFixed(1)}s`
1283
 
1284
+ // ── Demo mode fallback ────────────────────────────────────────────────────
1285
  const runDemo = async () => {
1286
  const steps = [
1287
+ { agent: 'analyzer', status: 'running', message: 'Scanning CUDA patterns\u2026', detail: '' },
1288
  { agent: 'analyzer', status: 'done', message: 'Found 3 critical AMD issues', detail: 'warp-32 assumption in reduction tail, threadIdx%32 idiom, LDS bank conflict pattern' },
1289
+ { agent: 'translator', status: 'running', message: 'Running hipify + LLM pass\u2026', detail: '' },
1290
  { agent: 'translator', status: 'done', message: 'Translation complete', detail: 'hipify applied; 7 additional LLM corrections for wavefront-64 semantics' },
1291
+ { agent: 'optimizer', status: 'running', message: 'Proposing optimizations\u2026', detail: '' },
1292
  { agent: 'optimizer', status: 'done', message: '4 optimization patches generated', detail: 'LDS padding, wavefront-aware reduction, coalesced access pattern' },
1293
+ { agent: 'tester', status: 'running', message: 'Compiling with hipcc\u2026', detail: '' },
1294
+ { agent: 'tester', status: 'done', message: 'Compiled and profiled on gfx942', detail: 'rocprof: 0.026 ms \u2014 correctness verified' },
1295
+ { agent: 'coordinator', status: 'running', message: 'Assembling final report\u2026', detail: '' },
1296
+ { agent: 'coordinator', status: 'done', message: 'Migration complete \u2014 2.61\u00d7 speedup', detail: 'data_source: demo_artifact' },
1297
  ]
1298
 
1299
  for (const step of steps) {
 
1311
  setRunning(false)
1312
  }
1313
 
1314
+ // ── Main action ───────────────────────────────────────────────────────────
1315
  const handlePort = async () => {
1316
  if (running || !code.trim()) return
1317
 
 
1344
 
1345
  buf += dec.decode(value, { stream: true })
1346
  const lines = buf.split('\n')
1347
+ buf = lines.pop()
1348
 
1349
  for (const line of lines) {
1350
  if (!line.startsWith('data: ')) continue
 
1361
  detail: ev.detail ?? '',
1362
  })
1363
 
 
1364
  if (ev.agent === 'coordinator' && ev.status === 'done') {
1365
  let report = ev.result ?? null
1366
  if (!report && ev.detail) {
1367
+ try { report = JSON.parse(ev.detail) } catch (_) { report = null }
 
 
 
 
1368
  }
1369
  const r = report ?? ev
1370
  setBenchmark({
1371
+ total_changes: r.total_changes ?? r.changes_made ?? '\u2014',
1372
+ bugs_found: r.bugs_found ?? r.critical_bugs ?? r.static_risk_report?.critical_count ?? '\u2014',
1373
  compiled_successfully: r.compiled_successfully ?? r.compiled ?? r.migration_success ?? false,
1374
  data_source: r.data_source ?? 'unknown',
1375
  })
 
1378
  }
1379
  }
1380
  } catch {
1381
+ setErrorBanner('Backend unavailable \u2014 running in demo mode')
1382
  runDemo()
1383
+ return
1384
  }
1385
 
1386
  stopTimer()
1387
  setRunning(false)
1388
  }
1389
 
1390
+ // ── Segment data ──────────────────────────────────────────────────────────
1391
+ const segLabels = ['ANA', 'TRA', 'OPT', 'TES', 'CORD']
1392
+ const segAgents = ['analyzer', 'translator', 'optimizer', 'tester', 'coordinator']
 
 
 
 
 
 
 
 
 
 
 
 
1393
 
1394
+ const cardStyle = (status) => ({
1395
+ borderLeft: STATUS[status]?.borderLeft || '2px solid #1a1a1a',
1396
+ boxShadow: STATUS[status]?.cardShadow || 'none',
1397
+ background: '#0f0f0f',
1398
+ })
1399
 
1400
+ // ── Render ────────────────────────────────────────────────────────────────
1401
+ return (
1402
+ <>
1403
+ <style dangerouslySetInnerHTML={{ __html: globalCSS }} />
1404
+
1405
+ <ROCmCursor running={running} />
1406
+ <AetherFlowHero running={running} mousePos={mousePos} />
1407
+
1408
+ <div style={{
1409
+ minHeight: '100vh',
1410
+ display: 'flex',
1411
+ flexDirection: 'column',
1412
+ background: 'rgba(8,8,8,0.82)',
1413
+ color: '#f0f0f0',
1414
+ fontFamily: '"JetBrains Mono", monospace',
1415
+ }}>
1416
+
1417
+ {/* ── Error banner ─────────────────────────────────────────────── */}
1418
+ {errorBanner && (
1419
+ <div style={{
1420
+ flexShrink: 0,
1421
+ padding: '8px 24px',
1422
+ background: '#0c0000',
1423
+ borderBottom: '1px solid #ff3366',
1424
+ color: '#ff3366',
1425
+ fontFamily: '"JetBrains Mono", monospace',
1426
+ fontSize: '12px',
1427
+ }}>
1428
+ \u26a0 {errorBanner}
1429
  </div>
1430
+ )}
1431
+
1432
+ {/* ── NAVBAR ───────────────────────────────────────────────────── */}
1433
+ <nav style={{
1434
+ flexShrink: 0,
1435
+ height: '40px',
1436
+ background: '#080808',
1437
+ borderBottom: '1px solid #1a1a1a',
1438
+ position: 'sticky',
1439
+ top: 0,
1440
+ zIndex: 50,
1441
+ display: 'flex',
1442
+ alignItems: 'center',
1443
+ justifyContent: 'space-between',
1444
+ padding: '0 20px',
1445
+ }}>
1446
+ <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
1447
+ <span className="clash-display" style={{ fontSize: '16px', fontWeight: 700, letterSpacing: '-0.02em', display: 'inline-flex', alignItems: 'center' }}>
1448
+ <AnimatedShinyText>
1449
+ <span style={{ color: '#f0f0f0' }}>ROCmPort</span>
1450
+ </AnimatedShinyText>
1451
+ <span style={{ color: '#b8ff57' }}>AI</span>
1452
+ </span>
1453
+ <HeroBadge color="gold">AMD MI300X</HeroBadge>
 
 
 
 
 
 
 
 
 
 
 
 
1454
  </div>
1455
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1456
+ <span style={{
1457
+ fontFamily: '"JetBrains Mono", monospace',
1458
+ fontSize: '13px',
1459
+ color: running ? '#b8ff57' : '#333333',
1460
+ transition: 'color 0.3s',
1461
+ }}>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1462
  {fmtElapsed(elapsed)}
1463
  </span>
1464
+ <span style={{
1465
+ width: '7px',
1466
+ height: '7px',
1467
+ borderRadius: '50%',
1468
+ background: running ? '#ff4d00' : (benchmark ? '#b8ff57' : '#2a2a2a'),
1469
+ animation: running ? 'nav-dot-pulse 1s ease-in-out infinite' : 'none',
1470
+ display: 'inline-block',
1471
+ flexShrink: 0,
1472
+ }} />
1473
  </div>
1474
+ </nav>
1475
+
1476
+ {/* ── HERO STRIP ───────────────────────────────────────────────── */}
1477
+ <ModernAnimatedHero />
1478
+
1479
+ {/* ── TWO-COLUMN MAIN ──────────────────────────────────────────── */}
1480
+ <div style={{ display: 'flex', flex: 1, overflow: 'hidden' }}>
1481
+
1482
+ {/* ── LEFT PANEL 58% ─────────────────────────────────────────── */}
1483
+ <div style={{
1484
+ width: '58%',
1485
+ display: 'flex',
1486
+ flexDirection: 'column',
1487
+ padding: '20px',
1488
+ gap: '16px',
1489
+ borderRight: '1px solid #1a1a1a',
1490
+ overflowY: 'auto',
1491
+ }}>
1492
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
1493
+ <span style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: '11px', color: '#555555' }}>// CUDA source</span>
1494
+ <span style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: '11px', color: '#555555' }}>{lineCount} lines</span>
1495
+ </div>
1496
 
1497
+ <textarea
1498
+ value={code}
1499
+ onChange={e => { setCode(e.target.value); setActiveTemplate(null) }}
1500
+ placeholder={'// Paste CUDA code here\n// or pick a demo below'}
1501
+ spellCheck={false}
1502
+ style={{
1503
+ width: '100%',
1504
+ minHeight: '340px',
1505
+ resize: 'vertical',
1506
+ background: '#0c0c0c',
1507
+ border: '1px solid #1a1a1a',
1508
+ borderRadius: '4px',
1509
+ padding: '16px',
1510
+ color: '#e8e8e8',
1511
+ fontFamily: '"JetBrains Mono", monospace',
1512
+ fontSize: '13px',
1513
+ lineHeight: '1.65',
1514
+ caretColor: '#b8ff57',
1515
+ tabSize: 4,
1516
+ outline: 'none',
1517
+ transition: 'border-color 0.15s, box-shadow 0.15s',
1518
+ }}
1519
+ onFocus={e => {
1520
+ e.target.style.borderColor = '#b8ff57'
1521
+ e.target.style.boxShadow = '0 0 0 2px rgba(184,255,87,0.08)'
1522
+ }}
1523
+ onBlur={e => {
1524
+ e.target.style.borderColor = '#1a1a1a'
1525
+ e.target.style.boxShadow = 'none'
1526
+ }}
1527
+ />
1528
+
1529
+ <div>
1530
+ <p style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: '11px', color: '#555555', marginBottom: '10px', marginTop: 0 }}>
1531
+ Select a template:
1532
+ </p>
1533
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
1534
+ {Object.keys(TEMPLATES).map(name => (
1535
+ <button
1536
+ key={name}
1537
+ onClick={() => selectTemplate(name)}
1538
+ style={{
1539
+ border: activeTemplate === name ? '1px solid #b8ff57' : '1px solid #1a1a1a',
1540
+ background: activeTemplate === name ? 'rgba(184,255,87,0.06)' : '#0f0f0f',
1541
+ color: activeTemplate === name ? '#b8ff57' : '#888888',
1542
+ fontFamily: '"JetBrains Mono", monospace',
1543
+ fontSize: '12px',
1544
+ borderRadius: '4px',
1545
+ padding: '4px 12px',
1546
+ cursor: 'pointer',
1547
+ transition: 'border-color 0.15s, color 0.15s',
1548
+ }}
1549
+ onMouseEnter={e => {
1550
+ if (activeTemplate !== name) {
1551
+ e.currentTarget.style.borderColor = 'rgba(184,255,87,0.4)'
1552
+ e.currentTarget.style.color = 'rgba(184,255,87,0.6)'
1553
+ }
1554
+ }}
1555
+ onMouseLeave={e => {
1556
+ if (activeTemplate !== name) {
1557
+ e.currentTarget.style.borderColor = '#1a1a1a'
1558
+ e.currentTarget.style.color = '#888888'
1559
+ }
1560
+ }}
1561
+ >
1562
+ {name}
1563
+ </button>
1564
+ ))}
1565
+ </div>
1566
+ </div>
1567
+
1568
+ <MagneticButton onClick={handlePort} disabled={running || !code.trim()}>
1569
+ <AnimatedShinyText>
1570
+ <span style={{
1571
+ fontFamily: '"JetBrains Mono", monospace',
1572
+ fontSize: '14px',
1573
+ letterSpacing: '3px',
1574
+ textTransform: 'uppercase',
1575
+ fontWeight: 600,
1576
+ }}>
1577
+ {running ? 'RUNNING\u2026' : 'PORT TO ROCM'}
1578
+ </span>
1579
+ </AnimatedShinyText>
1580
+ </MagneticButton>
1581
  </div>
 
 
1582
 
1583
+ {/* ── RIGHT PANEL 42% (WrapShader owns the width) ─────────── */}
1584
+ <WrapShader active={running}>
1585
+ <div style={{
1586
+ display: 'flex',
1587
+ flexDirection: 'column',
1588
+ padding: '20px',
1589
+ gap: '16px',
1590
+ overflowY: 'auto',
1591
+ height: '100%',
1592
+ isolation: 'isolate',
1593
+ }}>
1594
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
1595
+ <span style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: '11px', color: '#555555' }}>// Pipeline</span>
1596
+ <span style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: '12px', color: running ? '#b8ff57' : '#333333', transition: 'color 0.3s' }}>
1597
+ {fmtElapsed(elapsed)}
 
 
 
 
 
 
 
 
1598
  </span>
1599
+ </div>
1600
+
1601
+ {/* Pipeline bar */}
1602
+ <div>
1603
+ <div style={{ display: 'flex', gap: '2px', height: '6px', marginBottom: '6px' }}>
1604
+ {segAgents.map((agent) => {
1605
+ const st = agents[agent].status
1606
+ const isRun = st === 'running'
1607
+ const isDone = st === 'done'
1608
+ return (
1609
+ <div key={agent} style={{
1610
+ flex: 1,
1611
+ borderRadius: '2px',
1612
+ background: isDone ? '#b8ff57' : isRun ? '#ff4d00' : '#1a1a1a',
1613
+ boxShadow: isRun ? '4px 0 12px rgba(255,77,0,0.6)' : 'none',
1614
+ transition: 'background 0.3s',
1615
+ }} />
1616
+ )
1617
+ })}
1618
+ </div>
1619
+ <div style={{ display: 'flex', gap: '2px' }}>
1620
+ {segLabels.map(lbl => (
1621
+ <div key={lbl} style={{ flex: 1, fontFamily: '"JetBrains Mono", monospace', fontSize: '9px', color: '#555555', textAlign: 'center' }}>
1622
+ {lbl}
1623
+ </div>
1624
+ ))}
1625
+ </div>
1626
+ </div>
1627
+
1628
+ {/* Agent cards */}
1629
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
1630
+ {AGENT_LIST.map(agent => (
1631
+ <HeroDitheringCard key={agent} style={cardStyle(agents[agent].status)}>
1632
+ <AgentCard name={agent} state={agents[agent]} />
1633
+ </HeroDitheringCard>
1634
+ ))}
1635
  </div>
1636
  </div>
1637
+ </WrapShader>
1638
+
1639
  </div>
1640
+
1641
+ {/* ── BENCHMARK FOOTER ─────────────────────────────────────────── */}
1642
+ {benchmark && (
1643
+ <div className="benchmark-footer" style={{
1644
+ flexShrink: 0,
1645
+ display: 'flex',
1646
+ flexWrap: 'wrap',
1647
+ gap: '24px',
1648
+ padding: '16px 24px',
1649
+ background: '#0c0c0c',
1650
+ borderTop: '1px solid #1a1a1a',
1651
+ }}>
1652
+ {[
1653
+ { label: 'CHANGES MADE', value: benchmark.total_changes, color: '#ffd60a' },
1654
+ { label: 'BUGS FOUND', value: benchmark.bugs_found, color: '#ff3366' },
1655
+ {
1656
+ label: 'COMPILE STATUS',
1657
+ value: benchmark.compiled_successfully ? 'SUCCESS' : 'FAILED',
1658
+ color: benchmark.compiled_successfully ? '#b8ff57' : '#ff3366',
1659
+ },
1660
+ { label: 'DATA SOURCE', value: benchmark.data_source, color: '#b3e8ff', isSource: true },
1661
+ ].map(({ label, value, color, isSource }) => (
1662
+ <div key={label} style={{ display: 'flex', flexDirection: 'column', gap: '4px', minWidth: '120px' }}>
1663
+ <span style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: '10px', color: '#555555', textTransform: 'uppercase', letterSpacing: '0.15em' }}>
1664
+ {label}
1665
+ </span>
1666
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
1667
+ <AnimatedShinyText>
1668
+ <span style={{ fontFamily: '"JetBrains Mono", monospace', fontSize: '24px', fontWeight: 600, color, lineHeight: 1.1 }}>
1669
+ {String(value ?? '\u2014')}
1670
+ </span>
1671
+ </AnimatedShinyText>
1672
+ {isSource && value === 'real_rocm' && (
1673
+ <HeroBadge color="green">LIVE HARDWARE</HeroBadge>
1674
+ )}
1675
+ </div>
1676
+ </div>
1677
+ ))}
1678
+ </div>
1679
+ )}
1680
+
1681
+ </div>
1682
+ </>
1683
  )
1684
  }
frontend/tailwind.config.js CHANGED
@@ -6,6 +6,7 @@ export default {
6
  fontFamily: {
7
  code: ['"JetBrains Mono"', 'monospace'],
8
  ui: ['Inter', 'sans-serif'],
 
9
  },
10
  keyframes: {
11
  'rocm-pulse': {
 
6
  fontFamily: {
7
  code: ['"JetBrains Mono"', 'monospace'],
8
  ui: ['Inter', 'sans-serif'],
9
+ display: ['"Clash Display"', 'sans-serif'],
10
  },
11
  keyframes: {
12
  'rocm-pulse': {