AlanCantoFTW commited on
Commit
0d2cfe3
·
verified ·
1 Parent(s): 9104d57

Feature: Real-Time Highway Hazard Evasion Canvas Simulator (ProKope <25ms vs Cloud LLM 1.2s lag)

Browse files
Files changed (1) hide show
  1. index.html +584 -1
index.html CHANGED
@@ -455,12 +455,93 @@
455
  border-radius: 3px;
456
  transition: width 0.4s ease;
457
  }
458
-
459
  .prim-desc {
460
  font-size: 11px;
461
  color: var(--text-muted);
462
  }
463
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
  /* LEADERBOARD TABLE */
465
  .table-container {
466
  background: var(--bg-card);
@@ -669,6 +750,59 @@
669
  </div>
670
  </section>
671
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
672
  <!-- BENCHMARK TABLE -->
673
  <section>
674
  <div class="section-header">
@@ -935,6 +1069,455 @@
935
 
936
  // Initialize with first scenario
937
  setScenario(0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
938
  </script>
939
  </body>
940
  </html>
 
455
  border-radius: 3px;
456
  transition: width 0.4s ease;
457
  }
 
458
  .prim-desc {
459
  font-size: 11px;
460
  color: var(--text-muted);
461
  }
462
 
463
+ /* AUTONOMOUS AGENT SIMULATOR */
464
+ .agent-sim-card {
465
+ background: var(--bg-card);
466
+ border: 1px solid var(--border-accent);
467
+ border-radius: 20px;
468
+ padding: 32px;
469
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), 0 0 30px rgba(0, 229, 255, 0.08);
470
+ margin-bottom: 80px;
471
+ }
472
+ .canvas-container {
473
+ position: relative;
474
+ width: 100%;
475
+ background: #06090f;
476
+ border: 1px solid rgba(0, 229, 255, 0.25);
477
+ border-radius: 14px;
478
+ overflow: hidden;
479
+ margin: 20px 0;
480
+ box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.85);
481
+ }
482
+ #simCanvas {
483
+ width: 100%;
484
+ height: auto;
485
+ display: block;
486
+ cursor: crosshair;
487
+ }
488
+ .sim-mode-toggle {
489
+ display: inline-flex;
490
+ background: rgba(0, 0, 0, 0.55);
491
+ border: 1px solid var(--border);
492
+ border-radius: 10px;
493
+ padding: 4px;
494
+ gap: 6px;
495
+ }
496
+ .mode-btn {
497
+ padding: 8px 16px;
498
+ border-radius: 7px;
499
+ border: none;
500
+ font-size: 13px;
501
+ font-weight: 600;
502
+ cursor: pointer;
503
+ color: var(--text-muted);
504
+ background: transparent;
505
+ transition: all 0.2s;
506
+ }
507
+ .mode-btn.active-prokope {
508
+ background: linear-gradient(135deg, var(--blue), var(--cyan));
509
+ color: #000;
510
+ font-weight: 700;
511
+ box-shadow: 0 0 15px var(--cyan-glow);
512
+ }
513
+ .mode-btn.active-cloud {
514
+ background: linear-gradient(135deg, #d50000, #ff5252);
515
+ color: #fff;
516
+ font-weight: 700;
517
+ box-shadow: 0 0 15px rgba(255, 23, 68, 0.4);
518
+ }
519
+ .agent-hud {
520
+ display: grid;
521
+ grid-template-columns: repeat(4, 1fr);
522
+ gap: 14px;
523
+ background: rgba(0, 0, 0, 0.35);
524
+ border: 1px solid var(--border);
525
+ border-radius: 12px;
526
+ padding: 16px 20px;
527
+ }
528
+ .hud-stat-title {
529
+ font-size: 11px;
530
+ text-transform: uppercase;
531
+ letter-spacing: 0.8px;
532
+ color: var(--text-muted);
533
+ margin-bottom: 4px;
534
+ }
535
+ .hud-stat-val {
536
+ font-family: 'Outfit', sans-serif;
537
+ font-size: 17px;
538
+ font-weight: 700;
539
+ color: #fff;
540
+ }
541
+ @media (max-width: 768px) {
542
+ .agent-hud { grid-template-columns: repeat(2, 1fr); }
543
+ }
544
+
545
  /* LEADERBOARD TABLE */
546
  .table-container {
547
  background: var(--bg-card);
 
750
  </div>
751
  </section>
752
 
753
+ <!-- REAL-TIME EDGE AGENT SIMULATOR -->
754
+ <section>
755
+ <div class="section-header">
756
+ <div class="badge" style="margin-bottom: 12px;">
757
+ <span class="badge-dot"></span> Edge Robotics &amp; Closed-Loop Control
758
+ </div>
759
+ <h3>Real-Time Highway Hazard Evasion Simulator</h3>
760
+ <p>Witness why 20ms System 1 decision models can pilot high-speed autonomous agents where cloud LLMs crash.</p>
761
+ </div>
762
+
763
+ <div class="agent-sim-card">
764
+ <div class="sim-top">
765
+ <div>
766
+ <div class="sim-title">
767
+ <span style="color: var(--cyan)">🏎️</span> Highway Collision Avoidance Vector
768
+ </div>
769
+ <p style="font-size: 13px; color: var(--text-muted); margin-top: 4px;">Click any lane on the road to manually spawn hazard roadblocks.</p>
770
+ </div>
771
+ <div style="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;">
772
+ <div class="sim-mode-toggle">
773
+ <button class="mode-btn active-prokope" id="btn-mode-prokope" onclick="setAgentMode('prokope')">⚡ ProKope-421M (&lt;25ms)</button>
774
+ <button class="mode-btn" id="btn-mode-cloud" onclick="setAgentMode('cloud')">⏳ Cloud LLM (1.2s Lag)</button>
775
+ </div>
776
+ <button class="scenario-btn" onclick="spawnHazardManual()">⚠️ Drop Hazard</button>
777
+ <button class="scenario-btn" onclick="resetAgentSim()">🔄 Reset</button>
778
+ </div>
779
+ </div>
780
+
781
+ <div class="canvas-container">
782
+ <canvas id="simCanvas" width="860" height="320"></canvas>
783
+ </div>
784
+
785
+ <div class="agent-hud">
786
+ <div>
787
+ <div class="hud-stat-title">Decision Latency</div>
788
+ <div class="hud-stat-val" id="hud-latency" style="color: var(--cyan);">&lt;21.4 ms</div>
789
+ </div>
790
+ <div>
791
+ <div class="hud-stat-title">Choice (Maneuver)</div>
792
+ <div class="hud-stat-val" id="hud-choice">Lane 2 (Cruising)</div>
793
+ </div>
794
+ <div>
795
+ <div class="hud-stat-title">Noul (Collision Hazard)</div>
796
+ <div class="hud-stat-val" id="hud-noul" style="color: #00e676;">CLEAR (0.021)</div>
797
+ </div>
798
+ <div>
799
+ <div class="hud-stat-title">Score (Throttle / Speed)</div>
800
+ <div class="hud-stat-val" id="hud-score" style="color: #ffd700;">0.850 (65 MPH)</div>
801
+ </div>
802
+ </div>
803
+ </div>
804
+ </section>
805
+
806
  <!-- BENCHMARK TABLE -->
807
  <section>
808
  <div class="section-header">
 
1069
 
1070
  // Initialize with first scenario
1071
  setScenario(0);
1072
+
1073
+ // =========================================================================
1074
+ // REAL-TIME HIGHWAY HAZARD EVASION SIMULATOR (SYSTEM 1 CLOSED-LOOP ENGINE)
1075
+ // =========================================================================
1076
+ const canvas = document.getElementById('simCanvas');
1077
+ const ctx = canvas.getContext('2d');
1078
+
1079
+ let agentMode = 'prokope'; // 'prokope' or 'cloud'
1080
+ let roadOffset = 0;
1081
+ let frameCount = 0;
1082
+ let obstacles = [];
1083
+ let particles = [];
1084
+ let explosions = [];
1085
+ let screenShake = 0;
1086
+ let cloudTimer = 0; // frames delayed
1087
+ let cloudState = 'normal'; // 'normal', 'thinking', 'crashed'
1088
+ let cloudProgress = 0;
1089
+
1090
+ const lanes = [65, 160, 255]; // Y coordinates of lane centers
1091
+
1092
+ const car = {
1093
+ x: 120,
1094
+ y: 160,
1095
+ lane: 1,
1096
+ targetLane: 1,
1097
+ width: 62,
1098
+ height: 32,
1099
+ speed: 65,
1100
+ isCrashed: false
1101
+ };
1102
+
1103
+ function setAgentMode(mode) {
1104
+ agentMode = mode;
1105
+ document.getElementById('btn-mode-prokope').className = mode === 'prokope' ? 'mode-btn active-prokope' : 'mode-btn';
1106
+ document.getElementById('btn-mode-cloud').className = mode === 'cloud' ? 'mode-btn active-cloud' : 'mode-btn';
1107
+ resetAgentSim();
1108
+ }
1109
+
1110
+ function resetAgentSim() {
1111
+ obstacles = [];
1112
+ particles = [];
1113
+ explosions = [];
1114
+ car.lane = 1;
1115
+ car.targetLane = 1;
1116
+ car.y = lanes[1];
1117
+ car.isCrashed = false;
1118
+ cloudTimer = 0;
1119
+ cloudState = 'normal';
1120
+ cloudProgress = 0;
1121
+ updateHud();
1122
+ }
1123
+
1124
+ function spawnHazard(laneIdx, customX = 880) {
1125
+ obstacles.push({
1126
+ x: customX,
1127
+ y: lanes[laneIdx],
1128
+ lane: laneIdx,
1129
+ width: 44,
1130
+ height: 32,
1131
+ passed: false,
1132
+ evaluated: false
1133
+ });
1134
+ }
1135
+
1136
+ function spawnHazardManual() {
1137
+ // Spawn hazard in current lane of the car
1138
+ spawnHazard(car.lane, 860);
1139
+ }
1140
+
1141
+ // Canvas click to spawn hazard in specific lane
1142
+ canvas.addEventListener('click', (e) => {
1143
+ const rect = canvas.getBoundingClientRect();
1144
+ const scaleY = canvas.height / rect.height;
1145
+ const clickY = (e.clientY - rect.top) * scaleY;
1146
+ let clickedLane = 1;
1147
+ if (clickY < 110) clickedLane = 0;
1148
+ else if (clickY > 210) clickedLane = 2;
1149
+ spawnHazard(clickedLane, 860);
1150
+ });
1151
+
1152
+ function updateHud() {
1153
+ const latEl = document.getElementById('hud-latency');
1154
+ const choEl = document.getElementById('hud-choice');
1155
+ const nouEl = document.getElementById('hud-noul');
1156
+ const scoEl = document.getElementById('hud-score');
1157
+
1158
+ if (agentMode === 'prokope') {
1159
+ latEl.style.color = 'var(--cyan)';
1160
+ latEl.innerText = '<21.4 ms';
1161
+ choEl.innerText = `Lane ${car.targetLane + 1} (${car.lane !== car.targetLane ? 'Evasion Vector' : 'Cruising'})`;
1162
+ nouEl.style.color = car.isCrashed ? '#ff1744' : (car.lane !== car.targetLane ? '#ffd700' : '#00e676');
1163
+ nouEl.innerText = car.isCrashed ? 'CRASH (0.999)' : (car.lane !== car.targetLane ? 'HAZARD: EVADING (0.994)' : 'CLEAR (0.012)');
1164
+ scoEl.innerText = `0.850 (${car.speed} MPH)`;
1165
+ } else {
1166
+ if (cloudState === 'thinking') {
1167
+ latEl.style.color = '#ff9100';
1168
+ latEl.innerText = '1,200 ms (Awaiting Tokens...)';
1169
+ choEl.innerText = 'STREAMING JSON...';
1170
+ nouEl.style.color = '#ff9100';
1171
+ nouEl.innerText = 'PROCESSING (Pending)';
1172
+ scoEl.innerText = '0.000 (Stalled)';
1173
+ } else if (cloudState === 'crashed') {
1174
+ latEl.style.color = '#ff1744';
1175
+ latEl.innerText = '1,240 ms (Reaction Failed)';
1176
+ choEl.innerText = '💥 IMPACT CRASH';
1177
+ nouEl.style.color = '#ff1744';
1178
+ nouEl.innerText = 'FATAL BREACH';
1179
+ scoEl.innerText = '0.000 (Impact)';
1180
+ } else {
1181
+ latEl.style.color = '#ff9100';
1182
+ latEl.innerText = '~1,200 ms (Cloud SLA)';
1183
+ choEl.innerText = `Lane ${car.lane + 1} (Cruising)`;
1184
+ nouEl.style.color = '#00e676';
1185
+ nouEl.innerText = 'CLEAR (0.015)';
1186
+ scoEl.innerText = `0.850 (${car.speed} MPH)`;
1187
+ }
1188
+ }
1189
+ }
1190
+
1191
+ function createExplosion(x, y) {
1192
+ screenShake = 16;
1193
+ for (let i = 0; i < 35; i++) {
1194
+ const angle = Math.random() * Math.PI * 2;
1195
+ const spd = 2 + Math.random() * 6;
1196
+ explosions.push({
1197
+ x: x,
1198
+ y: y,
1199
+ vx: Math.cos(angle) * spd,
1200
+ vy: Math.sin(angle) * spd,
1201
+ radius: 2 + Math.random() * 4,
1202
+ life: 1.0,
1203
+ color: Math.random() > 0.4 ? '#ff1744' : '#ff9100'
1204
+ });
1205
+ }
1206
+ }
1207
+
1208
+ function loop() {
1209
+ frameCount++;
1210
+ roadOffset = (roadOffset + 8) % 40;
1211
+
1212
+ // Screen shake damping
1213
+ let offsetX = 0;
1214
+ let offsetY = 0;
1215
+ if (screenShake > 0) {
1216
+ offsetX = (Math.random() - 0.5) * screenShake;
1217
+ offsetY = (Math.random() - 0.5) * screenShake;
1218
+ screenShake *= 0.85;
1219
+ if (screenShake < 0.5) screenShake = 0;
1220
+ }
1221
+
1222
+ ctx.save();
1223
+ ctx.translate(offsetX, offsetY);
1224
+
1225
+ // Clear canvas
1226
+ ctx.fillStyle = '#06090f';
1227
+ ctx.fillRect(-20, -20, canvas.width + 40, canvas.height + 40);
1228
+
1229
+ // Draw road asphalt
1230
+ ctx.fillStyle = '#0b0f19';
1231
+ ctx.fillRect(0, 10, canvas.width, 300);
1232
+
1233
+ // Road outer border lines
1234
+ ctx.strokeStyle = 'rgba(0, 229, 255, 0.4)';
1235
+ ctx.lineWidth = 3;
1236
+ ctx.shadowBlur = 8;
1237
+ ctx.shadowColor = 'var(--cyan)';
1238
+ ctx.beginPath();
1239
+ ctx.moveTo(0, 10);
1240
+ ctx.lineTo(canvas.width, 10);
1241
+ ctx.moveTo(0, 310);
1242
+ ctx.lineTo(canvas.width, 310);
1243
+ ctx.stroke();
1244
+ ctx.shadowBlur = 0;
1245
+
1246
+ // Dashed lane dividers
1247
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';
1248
+ ctx.lineWidth = 2;
1249
+ ctx.setLineDash([25, 20]);
1250
+ ctx.lineDashOffset = -roadOffset;
1251
+ ctx.beginPath();
1252
+ ctx.moveTo(0, 110);
1253
+ ctx.lineTo(canvas.width, 110);
1254
+ ctx.moveTo(0, 210);
1255
+ ctx.lineTo(canvas.width, 210);
1256
+ ctx.stroke();
1257
+ ctx.setLineDash([]);
1258
+
1259
+ // Auto-spawn obstacles
1260
+ if (frameCount % 130 === 0 && !car.isCrashed) {
1261
+ // Pick a random lane
1262
+ const randLane = Math.floor(Math.random() * 3);
1263
+ spawnHazard(randLane);
1264
+ }
1265
+
1266
+ // Smooth vehicle lane interpolation
1267
+ const targetY = lanes[car.targetLane];
1268
+ if (!car.isCrashed) {
1269
+ car.y += (targetY - car.y) * 0.16;
1270
+ if (Math.abs(car.y - targetY) < 1.5) {
1271
+ car.lane = car.targetLane;
1272
+ }
1273
+ }
1274
+
1275
+ // Exhaust particles
1276
+ if (!car.isCrashed && frameCount % 2 === 0) {
1277
+ particles.push({
1278
+ x: car.x - 28,
1279
+ y: car.y + (Math.random() - 0.5) * 6,
1280
+ vx: -(3 + Math.random() * 2),
1281
+ vy: (Math.random() - 0.5) * 1.5,
1282
+ life: 1.0,
1283
+ color: agentMode === 'prokope' ? 'rgba(0, 229, 255,' : 'rgba(255, 82, 82,'
1284
+ });
1285
+ }
1286
+
1287
+ // Draw & update exhaust particles
1288
+ for (let i = particles.length - 1; i >= 0; i--) {
1289
+ const p = particles[i];
1290
+ p.x += p.vx;
1291
+ p.y += p.vy;
1292
+ p.life -= 0.05;
1293
+ if (p.life <= 0) {
1294
+ particles.splice(i, 1);
1295
+ continue;
1296
+ }
1297
+ ctx.fillStyle = `${p.color} ${p.life})`;
1298
+ ctx.beginPath();
1299
+ ctx.arc(p.x, p.y, 2.5 * p.life, 0, Math.PI * 2);
1300
+ ctx.fill();
1301
+ }
1302
+
1303
+ // Sensor raycast logic
1304
+ const sensorRange = 300;
1305
+ let imminentHazard = null;
1306
+
1307
+ // Move & render obstacles
1308
+ for (let i = obstacles.length - 1; i >= 0; i--) {
1309
+ const obs = obstacles[i];
1310
+ if (!car.isCrashed) {
1311
+ obs.x -= 5.5;
1312
+ }
1313
+
1314
+ // Check if obstacle is inside sensor cone (same lane, ahead of car)
1315
+ if (obs.lane === car.targetLane && obs.x > car.x && obs.x < car.x + sensorRange) {
1316
+ imminentHazard = obs;
1317
+ }
1318
+
1319
+ // Collision check
1320
+ const xDist = Math.abs(obs.x - car.x);
1321
+ const yDist = Math.abs(obs.y - car.y);
1322
+ if (xDist < 45 && yDist < 25 && !car.isCrashed) {
1323
+ car.isCrashed = true;
1324
+ createExplosion(car.x + 20, car.y);
1325
+ if (agentMode === 'cloud') {
1326
+ cloudState = 'crashed';
1327
+ }
1328
+ updateHud();
1329
+ setTimeout(() => {
1330
+ resetAgentSim();
1331
+ }, 2400);
1332
+ }
1333
+
1334
+ // Remove offscreen
1335
+ if (obs.x < -60) {
1336
+ obstacles.splice(i, 1);
1337
+ continue;
1338
+ }
1339
+
1340
+ // Draw Obstacle (Futuristic Cyber-Barrier)
1341
+ ctx.fillStyle = '#ff1744';
1342
+ ctx.shadowColor = 'rgba(255, 23, 68, 0.7)';
1343
+ ctx.shadowBlur = 12;
1344
+ ctx.beginPath();
1345
+ if (ctx.roundRect) {
1346
+ ctx.roundRect(obs.x - obs.width / 2, obs.y - obs.height / 2, obs.width, obs.height, 6);
1347
+ } else {
1348
+ ctx.rect(obs.x - obs.width / 2, obs.y - obs.height / 2, obs.width, obs.height);
1349
+ }
1350
+ ctx.fill();
1351
+
1352
+ // Hazard stripes on barrier
1353
+ ctx.strokeStyle = '#ffffff';
1354
+ ctx.lineWidth = 3;
1355
+ ctx.beginPath();
1356
+ ctx.moveTo(obs.x - 12, obs.y - 10);
1357
+ ctx.lineTo(obs.x - 2, obs.y + 10);
1358
+ ctx.moveTo(obs.x + 2, obs.y - 10);
1359
+ ctx.lineTo(obs.x + 12, obs.y + 10);
1360
+ ctx.stroke();
1361
+ ctx.shadowBlur = 0;
1362
+ }
1363
+
1364
+ // Autonomous Decision Making Engine
1365
+ if (imminentHazard && !imminentHazard.evaluated && !car.isCrashed) {
1366
+ if (agentMode === 'prokope') {
1367
+ // PROKOPE: Sub-25ms Single Forward Pass Decision
1368
+ imminentHazard.evaluated = true;
1369
+ // Find safe lane: check which lane has no nearby obstacles
1370
+ const candidateLanes = [0, 1, 2].filter(l => l !== car.targetLane);
1371
+ // Score lanes by clearance
1372
+ let bestLane = candidateLanes[0];
1373
+ let maxClearance = -1;
1374
+ for (let cand of candidateLanes) {
1375
+ let clearance = 9999;
1376
+ for (let o of obstacles) {
1377
+ if (o.lane === cand && o.x > car.x - 50 && o.x < car.x + 500) {
1378
+ const dist = Math.abs(o.x - car.x);
1379
+ if (dist < clearance) clearance = dist;
1380
+ }
1381
+ }
1382
+ if (clearance > maxClearance) {
1383
+ maxClearance = clearance;
1384
+ bestLane = cand;
1385
+ }
1386
+ }
1387
+
1388
+ // Execute immediate lane swerve
1389
+ car.targetLane = bestLane;
1390
+ updateHud();
1391
+ } else {
1392
+ // CLOUD MODE: Artificial 1.2s Autoregressive Delay
1393
+ if (cloudState === 'normal') {
1394
+ cloudState = 'thinking';
1395
+ cloudProgress = 0;
1396
+ cloudTimer = 55; // ~1.1s lag
1397
+ updateHud();
1398
+ }
1399
+ }
1400
+ }
1401
+
1402
+ // Handle cloud thinking progress
1403
+ if (cloudState === 'thinking') {
1404
+ cloudProgress += 1.8;
1405
+ if (cloudProgress > 100) cloudProgress = 100;
1406
+ }
1407
+
1408
+ // Draw Lidar / Radar Sensor Raycast
1409
+ if (!car.isCrashed) {
1410
+ ctx.save();
1411
+ const beamColor = imminentHazard
1412
+ ? (agentMode === 'prokope' ? 'rgba(0, 230, 118, 0.25)' : 'rgba(255, 23, 68, 0.35)')
1413
+ : 'rgba(0, 229, 255, 0.12)';
1414
+ ctx.fillStyle = beamColor;
1415
+ ctx.beginPath();
1416
+ ctx.moveTo(car.x + 30, car.y);
1417
+ ctx.lineTo(car.x + sensorRange, car.y - 25);
1418
+ ctx.lineTo(car.x + sensorRange, car.y + 25);
1419
+ ctx.closePath();
1420
+ ctx.fill();
1421
+
1422
+ // Sensor beam outline
1423
+ ctx.strokeStyle = imminentHazard
1424
+ ? (agentMode === 'prokope' ? '#00e676' : '#ff1744')
1425
+ : 'rgba(0, 229, 255, 0.4)';
1426
+ ctx.lineWidth = 1.5;
1427
+ ctx.beginPath();
1428
+ ctx.moveTo(car.x + 30, car.y);
1429
+ ctx.lineTo(car.x + sensorRange, car.y);
1430
+ ctx.stroke();
1431
+ ctx.restore();
1432
+ }
1433
+
1434
+ // Draw Car (Sleek Cyber-Coupe)
1435
+ if (!car.isCrashed) {
1436
+ ctx.save();
1437
+ ctx.shadowColor = agentMode === 'prokope' ? 'rgba(0, 229, 255, 0.6)' : 'rgba(255, 82, 82, 0.6)';
1438
+ ctx.shadowBlur = 14;
1439
+
1440
+ // Main Car Body
1441
+ ctx.fillStyle = agentMode === 'prokope' ? '#00e5ff' : '#ff5252';
1442
+ ctx.beginPath();
1443
+ if (ctx.roundRect) {
1444
+ ctx.roundRect(car.x - car.width / 2, car.y - car.height / 2, car.width, car.height, 8);
1445
+ } else {
1446
+ ctx.rect(car.x - car.width / 2, car.y - car.height / 2, car.width, car.height);
1447
+ }
1448
+ ctx.fill();
1449
+
1450
+ // Cockpit canopy
1451
+ ctx.fillStyle = '#07090e';
1452
+ ctx.beginPath();
1453
+ if (ctx.roundRect) {
1454
+ ctx.roundRect(car.x - 8, car.y - 10, 26, 20, 5);
1455
+ } else {
1456
+ ctx.rect(car.x - 8, car.y - 10, 26, 20);
1457
+ }
1458
+ ctx.fill();
1459
+
1460
+ // Neon headlights
1461
+ ctx.fillStyle = '#ffffff';
1462
+ ctx.fillRect(car.x + car.width / 2 - 4, car.y - 12, 4, 6);
1463
+ ctx.fillRect(car.x + car.width / 2 - 4, car.y + 6, 4, 6);
1464
+
1465
+ ctx.restore();
1466
+
1467
+ // Cloud Thinking Token Balloon
1468
+ if (agentMode === 'cloud' && cloudState === 'thinking') {
1469
+ ctx.save();
1470
+ ctx.fillStyle = 'rgba(13, 18, 28, 0.9)';
1471
+ ctx.strokeStyle = '#ff9100';
1472
+ ctx.lineWidth = 1.5;
1473
+ ctx.beginPath();
1474
+ if (ctx.roundRect) {
1475
+ ctx.roundRect(car.x - 60, car.y - 55, 170, 32, 6);
1476
+ } else {
1477
+ ctx.rect(car.x - 60, car.y - 55, 170, 32);
1478
+ }
1479
+ ctx.fill();
1480
+ ctx.stroke();
1481
+
1482
+ ctx.fillStyle = '#ff9100';
1483
+ ctx.font = '10px monospace';
1484
+ ctx.fillText(`Generating JSON: ${Math.floor(cloudProgress)}%`, car.x - 50, car.y - 35);
1485
+ ctx.restore();
1486
+ }
1487
+ }
1488
+
1489
+ // Explosion Particles
1490
+ for (let i = explosions.length - 1; i >= 0; i--) {
1491
+ const ex = explosions[i];
1492
+ ex.x += ex.vx;
1493
+ ex.y += ex.vy;
1494
+ ex.life -= 0.035;
1495
+ if (ex.life <= 0) {
1496
+ explosions.splice(i, 1);
1497
+ continue;
1498
+ }
1499
+ ctx.fillStyle = ex.color;
1500
+ ctx.beginPath();
1501
+ ctx.arc(ex.x, ex.y, ex.radius * ex.life, 0, Math.PI * 2);
1502
+ ctx.fill();
1503
+ }
1504
+
1505
+ // Crash Banner Overlay
1506
+ if (car.isCrashed && agentMode === 'cloud') {
1507
+ ctx.save();
1508
+ ctx.fillStyle = 'rgba(255, 23, 68, 0.9)';
1509
+ ctx.font = 'bold 15px Outfit, sans-serif';
1510
+ ctx.textAlign = 'center';
1511
+ ctx.fillText('💥 COLLISION: 1,200ms Cloud Latency Lag Failed to Evade!', canvas.width / 2, canvas.height / 2);
1512
+ ctx.restore();
1513
+ }
1514
+
1515
+ ctx.restore();
1516
+ requestAnimationFrame(loop);
1517
+ }
1518
+
1519
+ // Start highway agent simulation loop
1520
+ requestAnimationFrame(loop);
1521
  </script>
1522
  </body>
1523
  </html>