soumalya-iitj commited on
Commit
cba7312
Β·
verified Β·
1 Parent(s): 655ee20

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +367 -275
index.html CHANGED
@@ -3,20 +3,8 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="description" content="Interactive Embodied AI Autonomous Vehicle Simulator - Real-time AI decision making and navigation">
7
- <meta name="keywords" content="AI, autonomous vehicles, simulation, embodied AI, robotics, machine learning">
8
- <meta name="author" content="Embodied AI Research">
9
  <title>πŸš— Embodied AI - Autonomous Vehicle Simulator</title>
10
 
11
- <!-- Open Graph Meta Tags for Social Sharing -->
12
- <meta property="og:title" content="Embodied AI Vehicle Simulator">
13
- <meta property="og:description" content="Interactive demonstration of autonomous vehicle AI with real-time decision making">
14
- <meta property="og:type" content="website">
15
- <meta property="og:image" content="https://via.placeholder.com/1200x630/667eea/ffffff?text=Embodied+AI+Vehicle+Simulator">
16
-
17
- <!-- Favicon -->
18
- <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>πŸš—</text></svg>">
19
-
20
  <style>
21
  * {
22
  margin: 0;
@@ -40,33 +28,12 @@
40
  text-align: center;
41
  backdrop-filter: blur(10px);
42
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
43
- position: relative;
44
  }
45
 
46
  .header h1 {
47
  font-size: clamp(1.8rem, 4vw, 2.5rem);
48
  margin-bottom: 10px;
49
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
50
- background: linear-gradient(45deg, #fff, #e0e0e0);
51
- -webkit-background-clip: text;
52
- -webkit-text-fill-color: transparent;
53
- background-clip: text;
54
- }
55
-
56
- .header p {
57
- font-size: clamp(0.9rem, 2.5vw, 1.1rem);
58
- opacity: 0.9;
59
- }
60
-
61
- .hf-badge {
62
- position: absolute;
63
- top: 10px;
64
- right: 20px;
65
- background: rgba(255, 255, 255, 0.2);
66
- padding: 5px 10px;
67
- border-radius: 15px;
68
- font-size: 0.8rem;
69
- backdrop-filter: blur(5px);
70
  }
71
 
72
  .main-container {
@@ -86,7 +53,6 @@
86
  padding: 20px;
87
  backdrop-filter: blur(10px);
88
  border: 1px solid rgba(255, 255, 255, 0.2);
89
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
90
  }
91
 
92
  .canvas-container {
@@ -96,7 +62,6 @@
96
  background: #1a1a2e;
97
  border-radius: 10px;
98
  overflow: hidden;
99
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
100
  border: 2px solid rgba(255, 255, 255, 0.1);
101
  }
102
 
@@ -115,7 +80,6 @@
115
  backdrop-filter: blur(10px);
116
  border: 1px solid rgba(255, 255, 255, 0.2);
117
  height: fit-content;
118
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
119
  }
120
 
121
  .control-section {
@@ -128,9 +92,6 @@
128
  color: #fff;
129
  border-bottom: 2px solid rgba(255, 255, 255, 0.3);
130
  padding-bottom: 8px;
131
- display: flex;
132
- align-items: center;
133
- gap: 8px;
134
  }
135
 
136
  .control-group {
@@ -145,26 +106,6 @@
145
  font-size: 0.9rem;
146
  }
147
 
148
- .control-group input, .control-group select {
149
- width: 100%;
150
- padding: 10px 12px;
151
- border: none;
152
- border-radius: 8px;
153
- background: rgba(255, 255, 255, 0.2);
154
- color: white;
155
- font-size: 14px;
156
- transition: background 0.3s ease;
157
- }
158
-
159
- .control-group input:focus, .control-group select:focus {
160
- outline: 2px solid rgba(255, 255, 255, 0.5);
161
- background: rgba(255, 255, 255, 0.3);
162
- }
163
-
164
- .control-group input::placeholder {
165
- color: rgba(255, 255, 255, 0.6);
166
- }
167
-
168
  .slider-container {
169
  display: flex;
170
  align-items: center;
@@ -173,6 +114,8 @@
173
 
174
  .slider-container input[type="range"] {
175
  flex: 1;
 
 
176
  }
177
 
178
  .slider-value {
@@ -184,6 +127,16 @@
184
  text-align: center;
185
  }
186
 
 
 
 
 
 
 
 
 
 
 
187
  .btn {
188
  width: 100%;
189
  padding: 12px;
@@ -194,41 +147,21 @@
194
  cursor: pointer;
195
  transition: all 0.3s ease;
196
  margin-bottom: 10px;
197
- position: relative;
198
- overflow: hidden;
199
- }
200
-
201
- .btn::before {
202
- content: '';
203
- position: absolute;
204
- top: 0;
205
- left: -100%;
206
- width: 100%;
207
- height: 100%;
208
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
209
- transition: left 0.5s;
210
- }
211
-
212
- .btn:hover::before {
213
- left: 100%;
214
  }
215
 
216
  .btn-primary {
217
  background: linear-gradient(45deg, #4CAF50, #45a049);
218
  color: white;
219
- box-shadow: 0 4px 15px rgba(76, 175, 80, 0.3);
220
  }
221
 
222
  .btn-secondary {
223
  background: linear-gradient(45deg, #2196F3, #1976D2);
224
  color: white;
225
- box-shadow: 0 4px 15px rgba(33, 150, 243, 0.3);
226
  }
227
 
228
  .btn-danger {
229
  background: linear-gradient(45deg, #f44336, #d32f2f);
230
  color: white;
231
- box-shadow: 0 4px 15px rgba(244, 67, 54, 0.3);
232
  }
233
 
234
  .btn:hover {
@@ -236,10 +169,6 @@
236
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
237
  }
238
 
239
- .btn:active {
240
- transform: translateY(0);
241
- }
242
-
243
  .btn:disabled {
244
  opacity: 0.6;
245
  cursor: not-allowed;
@@ -254,12 +183,6 @@
254
  border: 1px solid rgba(255, 255, 255, 0.1);
255
  }
256
 
257
- .stats h4 {
258
- margin-bottom: 12px;
259
- color: #fff;
260
- font-size: 1.1rem;
261
- }
262
-
263
  .stat-item {
264
  display: flex;
265
  justify-content: space-between;
@@ -268,10 +191,6 @@
268
  padding: 4px 0;
269
  }
270
 
271
- .stat-label {
272
- color: #ccc;
273
- }
274
-
275
  .stat-value {
276
  color: #4CAF50;
277
  font-weight: 600;
@@ -284,23 +203,6 @@
284
  border-radius: 8px;
285
  margin-top: 15px;
286
  font-size: 13px;
287
- line-height: 1.5;
288
- border: 1px solid rgba(255, 255, 255, 0.1);
289
- }
290
-
291
- .ai-info h4 {
292
- margin-bottom: 10px;
293
- color: #fff;
294
- }
295
-
296
- .ai-info ul {
297
- margin-left: 15px;
298
- margin-top: 8px;
299
- }
300
-
301
- .ai-info li {
302
- margin-bottom: 4px;
303
- color: #e0e0e0;
304
  }
305
 
306
  .current-decision {
@@ -334,29 +236,8 @@
334
  width: 16px;
335
  height: 16px;
336
  border-radius: 50%;
337
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
338
  }
339
 
340
- .footer {
341
- background: rgba(0, 0, 0, 0.3);
342
- padding: 15px;
343
- text-align: center;
344
- backdrop-filter: blur(10px);
345
- border-top: 1px solid rgba(255, 255, 255, 0.1);
346
- font-size: 0.9rem;
347
- color: rgba(255, 255, 255, 0.8);
348
- }
349
-
350
- .footer a {
351
- color: #4CAF50;
352
- text-decoration: none;
353
- }
354
-
355
- .footer a:hover {
356
- text-decoration: underline;
357
- }
358
-
359
- /* Mobile Responsive */
360
  @media (max-width: 768px) {
361
  .main-container {
362
  flex-direction: column;
@@ -370,64 +251,11 @@
370
  .canvas-container {
371
  height: 400px;
372
  }
373
-
374
- .header {
375
- padding: 15px;
376
- }
377
-
378
- .hf-badge {
379
- position: static;
380
- margin-top: 10px;
381
- display: inline-block;
382
- }
383
- }
384
-
385
- /* Loading Animation */
386
- .loading {
387
- display: flex;
388
- justify-content: center;
389
- align-items: center;
390
- position: absolute;
391
- top: 0;
392
- left: 0;
393
- right: 0;
394
- bottom: 0;
395
- background: rgba(26, 26, 46, 0.9);
396
- color: white;
397
- font-size: 18px;
398
- }
399
-
400
- .loading::after {
401
- content: '';
402
- width: 40px;
403
- height: 40px;
404
- border: 4px solid rgba(255, 255, 255, 0.3);
405
- border-top: 4px solid #4CAF50;
406
- border-radius: 50%;
407
- animation: spin 1s linear infinite;
408
- margin-left: 15px;
409
- }
410
-
411
- @keyframes spin {
412
- 0% { transform: rotate(0deg); }
413
- 100% { transform: rotate(360deg); }
414
- }
415
-
416
- /* Pulse animation for status indicators */
417
- .pulse {
418
- animation: pulse 2s infinite;
419
- }
420
-
421
- @keyframes pulse {
422
- 0% { opacity: 1; }
423
- 50% { opacity: 0.5; }
424
- 100% { opacity: 1; }
425
  }
426
  </style>
427
  </head>
428
  <body>
429
  <div class="header">
430
- <div class="hf-badge">πŸ€— Hugging Face Space</div>
431
  <h1>πŸš— Embodied AI Vehicle Simulator</h1>
432
  <p>Interactive autonomous vehicle navigation with real-time AI decision making</p>
433
  </div>
@@ -436,9 +264,6 @@
436
  <div class="simulation-area">
437
  <div class="canvas-container">
438
  <canvas id="simulationCanvas"></canvas>
439
- <div class="loading" id="loadingIndicator">
440
- Initializing AI System...
441
- </div>
442
  </div>
443
 
444
  <div class="legend">
@@ -474,7 +299,7 @@
474
  <div class="control-group">
475
  <label>Vehicle Speed</label>
476
  <div class="slider-container">
477
- <input type="range" id="speedSlider" min="0" max="5" value="2" step="0.5">
478
  <span class="slider-value" id="speedValue">2.0</span>
479
  </div>
480
  </div>
@@ -505,81 +330,69 @@
505
  <div class="stats">
506
  <h4>πŸ“Š Performance Metrics</h4>
507
  <div class="stat-item">
508
- <span class="stat-label">Distance Traveled:</span>
509
  <span class="stat-value" id="distanceTraveled">0m</span>
510
  </div>
511
  <div class="stat-item">
512
- <span class="stat-label">Targets Reached:</span>
513
  <span class="stat-value" id="targetsReached">0</span>
514
  </div>
515
  <div class="stat-item">
516
- <span class="stat-label">Obstacles Avoided:</span>
517
  <span class="stat-value" id="obstaclesAvoided">0</span>
518
  </div>
519
  <div class="stat-item">
520
- <span class="stat-label">AI Decisions/sec:</span>
521
- <span class="stat-value pulse" id="decisionsPerSec">0</span>
522
  </div>
523
  </div>
524
 
525
  <div class="ai-info">
526
  <h4>🧠 AI Decision Engine</h4>
527
- <div class="current-decision" id="currentDecision">System initializing...</div>
528
 
529
- <p><strong>Embodied AI Features:</strong></p>
530
  <ul>
531
  <li>Real-time sensor processing</li>
532
  <li>Dynamic path planning</li>
533
- <li>Multi-objective optimization</li>
534
- <li>Behavioral adaptation</li>
535
- <li>Environmental coupling</li>
536
  </ul>
537
  </div>
538
  </div>
539
  </div>
540
 
541
- <div class="footer">
542
- <p>
543
- Built with ❀️ for the AI community β€’
544
- <a href="https://huggingface.co/spaces" target="_blank">Hugging Face Spaces</a> β€’
545
- Click to add targets, Shift+Click for obstacles
546
- </p>
547
- </div>
548
-
549
  <script>
550
- // Enhanced simulator with better performance and mobile support
551
  const canvas = document.getElementById('simulationCanvas');
552
  const ctx = canvas.getContext('2d');
553
- const loadingIndicator = document.getElementById('loadingIndicator');
554
-
555
- // Performance optimization
556
- let devicePixelRatio = window.devicePixelRatio || 1;
557
 
558
  function resizeCanvas() {
559
  const container = canvas.parentElement;
560
  const rect = container.getBoundingClientRect();
561
-
562
- canvas.width = rect.width * devicePixelRatio;
563
- canvas.height = rect.height * devicePixelRatio;
564
- canvas.style.width = rect.width + 'px';
565
- canvas.style.height = rect.height + 'px';
566
-
567
- ctx.scale(devicePixelRatio, devicePixelRatio);
568
  }
569
 
570
  resizeCanvas();
571
  window.addEventListener('resize', resizeCanvas);
572
 
573
- // Simulation state
574
  let isRunning = false;
575
- let isPaused = false;
576
  let animationId = null;
577
- let lastTime = 0;
 
 
 
 
 
 
 
 
578
  let decisionCount = 0;
579
- let lastDecisionTime = 0;
580
- let frameCount = 0;
581
 
582
- // Enhanced Vehicle class with better AI
583
  class AutonomousVehicle {
584
  constructor(x, y) {
585
  this.x = x;
@@ -588,94 +401,373 @@
588
  this.vy = 0;
589
  this.angle = 0;
590
  this.speed = 2;
591
- this.maxSpeed = 5;
592
  this.size = 15;
593
  this.sensorRange = 100;
594
  this.sensors = [];
595
- this.path = [];
596
- this.currentTarget = null;
597
- this.distanceTraveled = 0;
598
  this.lastX = x;
599
  this.lastY = y;
600
- this.behavior = 'normal';
601
- this.avoidanceVector = { x: 0, y: 0 };
602
- this.stuckCounter = 0;
603
- this.lastPosition = { x: x, y: y };
604
- this.wanderAngle = 0;
605
  }
606
 
607
  updateSensors() {
608
  this.sensors = [];
609
- const numSensors = 12; // Increased for better detection
610
 
611
  for (let i = 0; i < numSensors; i++) {
612
  const angle = (i / numSensors) * 2 * Math.PI;
613
- const endX = this.x + Math.cos(angle) * this.sensorRange;
614
- const endY = this.y + Math.sin(angle) * this.sensorRange;
615
-
616
  let distance = this.sensorRange;
617
- let hitObstacle = false;
618
 
619
- // Check collision with obstacles
620
  for (let obstacle of obstacles) {
621
  const dx = obstacle.x - this.x;
622
  const dy = obstacle.y - this.y;
623
  const distToObstacle = Math.sqrt(dx * dx + dy * dy);
 
 
 
 
624
 
625
- if (distToObstacle > 0) {
626
- const angleToObstacle = Math.atan2(dy, dx);
627
- let angleDiff = Math.abs(angle - angleToObstacle);
628
- if (angleDiff > Math.PI) angleDiff = 2 * Math.PI - angleDiff;
629
-
630
- const detectionCone = 0.3; // Wider detection cone
631
- if (angleDiff < detectionCone) {
632
- const actualDistance = Math.max(0, distToObstacle - obstacle.size - 5);
633
- if (actualDistance < distance) {
634
- distance = actualDistance;
635
- hitObstacle = true;
636
- }
637
- }
638
  }
639
  }
640
 
641
- // Check canvas boundaries
642
- const boundaryDistance = this.checkBoundaryDistance(angle);
643
- if (boundaryDistance < distance) {
644
- distance = boundaryDistance;
645
- }
 
 
 
 
 
 
646
 
647
  this.sensors.push({
648
  angle: angle,
649
  distance: distance,
650
  x: this.x + Math.cos(angle) * distance,
651
- y: this.y + Math.sin(angle) * distance,
652
- hitObstacle: hitObstacle
653
  });
654
  }
655
  }
656
 
657
- checkBoundaryDistance(angle) {
658
- const canvasWidth = canvas.width / devicePixelRatio;
659
- const canvasHeight = canvas.height / devicePixelRatio;
660
 
661
- const cos = Math.cos(angle);
662
- const sin = Math.sin(angle);
 
663
 
664
- let distance = this.sensorRange;
 
 
 
 
 
 
665
 
666
- if (cos > 0) {
667
- distance = Math.min(distance, (canvasWidth - this.x) / cos);
668
- } else if (cos < 0) {
669
- distance = Math.min(distance, -this.x / cos);
 
 
 
 
 
 
 
670
  }
671
 
672
- if (sin > 0) {
673
- distance = Math.min(distance, (canvasHeight - this.y) / sin);
674
- } else if (sin < 0) {
675
- distance = Math.min(distance, -this.y / sin);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
676
  }
677
 
678
- return Math.max(0, distance - 10); // Margin from boundaries
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679
  }
680
  }
681
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
 
 
6
  <title>πŸš— Embodied AI - Autonomous Vehicle Simulator</title>
7
 
 
 
 
 
 
 
 
 
 
8
  <style>
9
  * {
10
  margin: 0;
 
28
  text-align: center;
29
  backdrop-filter: blur(10px);
30
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
 
31
  }
32
 
33
  .header h1 {
34
  font-size: clamp(1.8rem, 4vw, 2.5rem);
35
  margin-bottom: 10px;
36
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
 
39
  .main-container {
 
53
  padding: 20px;
54
  backdrop-filter: blur(10px);
55
  border: 1px solid rgba(255, 255, 255, 0.2);
 
56
  }
57
 
58
  .canvas-container {
 
62
  background: #1a1a2e;
63
  border-radius: 10px;
64
  overflow: hidden;
 
65
  border: 2px solid rgba(255, 255, 255, 0.1);
66
  }
67
 
 
80
  backdrop-filter: blur(10px);
81
  border: 1px solid rgba(255, 255, 255, 0.2);
82
  height: fit-content;
 
83
  }
84
 
85
  .control-section {
 
92
  color: #fff;
93
  border-bottom: 2px solid rgba(255, 255, 255, 0.3);
94
  padding-bottom: 8px;
 
 
 
95
  }
96
 
97
  .control-group {
 
106
  font-size: 0.9rem;
107
  }
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  .slider-container {
110
  display: flex;
111
  align-items: center;
 
114
 
115
  .slider-container input[type="range"] {
116
  flex: 1;
117
+ background: rgba(255, 255, 255, 0.2);
118
+ border-radius: 5px;
119
  }
120
 
121
  .slider-value {
 
127
  text-align: center;
128
  }
129
 
130
+ select {
131
+ width: 100%;
132
+ padding: 10px;
133
+ border: none;
134
+ border-radius: 8px;
135
+ background: rgba(255, 255, 255, 0.2);
136
+ color: white;
137
+ font-size: 14px;
138
+ }
139
+
140
  .btn {
141
  width: 100%;
142
  padding: 12px;
 
147
  cursor: pointer;
148
  transition: all 0.3s ease;
149
  margin-bottom: 10px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  }
151
 
152
  .btn-primary {
153
  background: linear-gradient(45deg, #4CAF50, #45a049);
154
  color: white;
 
155
  }
156
 
157
  .btn-secondary {
158
  background: linear-gradient(45deg, #2196F3, #1976D2);
159
  color: white;
 
160
  }
161
 
162
  .btn-danger {
163
  background: linear-gradient(45deg, #f44336, #d32f2f);
164
  color: white;
 
165
  }
166
 
167
  .btn:hover {
 
169
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
170
  }
171
 
 
 
 
 
172
  .btn:disabled {
173
  opacity: 0.6;
174
  cursor: not-allowed;
 
183
  border: 1px solid rgba(255, 255, 255, 0.1);
184
  }
185
 
 
 
 
 
 
 
186
  .stat-item {
187
  display: flex;
188
  justify-content: space-between;
 
191
  padding: 4px 0;
192
  }
193
 
 
 
 
 
194
  .stat-value {
195
  color: #4CAF50;
196
  font-weight: 600;
 
203
  border-radius: 8px;
204
  margin-top: 15px;
205
  font-size: 13px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  }
207
 
208
  .current-decision {
 
236
  width: 16px;
237
  height: 16px;
238
  border-radius: 50%;
 
239
  }
240
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  @media (max-width: 768px) {
242
  .main-container {
243
  flex-direction: column;
 
251
  .canvas-container {
252
  height: 400px;
253
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  }
255
  </style>
256
  </head>
257
  <body>
258
  <div class="header">
 
259
  <h1>πŸš— Embodied AI Vehicle Simulator</h1>
260
  <p>Interactive autonomous vehicle navigation with real-time AI decision making</p>
261
  </div>
 
264
  <div class="simulation-area">
265
  <div class="canvas-container">
266
  <canvas id="simulationCanvas"></canvas>
 
 
 
267
  </div>
268
 
269
  <div class="legend">
 
299
  <div class="control-group">
300
  <label>Vehicle Speed</label>
301
  <div class="slider-container">
302
+ <input type="range" id="speedSlider" min="0.5" max="5" value="2" step="0.5">
303
  <span class="slider-value" id="speedValue">2.0</span>
304
  </div>
305
  </div>
 
330
  <div class="stats">
331
  <h4>πŸ“Š Performance Metrics</h4>
332
  <div class="stat-item">
333
+ <span>Distance Traveled:</span>
334
  <span class="stat-value" id="distanceTraveled">0m</span>
335
  </div>
336
  <div class="stat-item">
337
+ <span>Targets Reached:</span>
338
  <span class="stat-value" id="targetsReached">0</span>
339
  </div>
340
  <div class="stat-item">
341
+ <span>Obstacles Avoided:</span>
342
  <span class="stat-value" id="obstaclesAvoided">0</span>
343
  </div>
344
  <div class="stat-item">
345
+ <span>AI Decisions/sec:</span>
346
+ <span class="stat-value" id="decisionsPerSec">0</span>
347
  </div>
348
  </div>
349
 
350
  <div class="ai-info">
351
  <h4>🧠 AI Decision Engine</h4>
352
+ <div class="current-decision" id="currentDecision">Ready to start simulation</div>
353
 
354
+ <p><strong>Features:</strong></p>
355
  <ul>
356
  <li>Real-time sensor processing</li>
357
  <li>Dynamic path planning</li>
358
+ <li>Obstacle avoidance</li>
359
+ <li>Target seeking behavior</li>
 
360
  </ul>
361
  </div>
362
  </div>
363
  </div>
364
 
 
 
 
 
 
 
 
 
365
  <script>
366
+ // Canvas setup
367
  const canvas = document.getElementById('simulationCanvas');
368
  const ctx = canvas.getContext('2d');
 
 
 
 
369
 
370
  function resizeCanvas() {
371
  const container = canvas.parentElement;
372
  const rect = container.getBoundingClientRect();
373
+ canvas.width = rect.width;
374
+ canvas.height = rect.height;
 
 
 
 
 
375
  }
376
 
377
  resizeCanvas();
378
  window.addEventListener('resize', resizeCanvas);
379
 
380
+ // Simulation variables
381
  let isRunning = false;
 
382
  let animationId = null;
383
+ let vehicle = null;
384
+ let obstacles = [];
385
+ let targets = [];
386
+ let stats = {
387
+ distanceTraveled: 0,
388
+ targetsReached: 0,
389
+ obstaclesAvoided: 0,
390
+ decisionsPerSecond: 0
391
+ };
392
  let decisionCount = 0;
393
+ let lastDecisionTime = Date.now();
 
394
 
395
+ // Vehicle class
396
  class AutonomousVehicle {
397
  constructor(x, y) {
398
  this.x = x;
 
401
  this.vy = 0;
402
  this.angle = 0;
403
  this.speed = 2;
 
404
  this.size = 15;
405
  this.sensorRange = 100;
406
  this.sensors = [];
 
 
 
407
  this.lastX = x;
408
  this.lastY = y;
409
+ this.wanderAngle = Math.random() * Math.PI * 2;
 
 
 
 
410
  }
411
 
412
  updateSensors() {
413
  this.sensors = [];
414
+ const numSensors = 8;
415
 
416
  for (let i = 0; i < numSensors; i++) {
417
  const angle = (i / numSensors) * 2 * Math.PI;
 
 
 
418
  let distance = this.sensorRange;
 
419
 
420
+ // Check obstacles
421
  for (let obstacle of obstacles) {
422
  const dx = obstacle.x - this.x;
423
  const dy = obstacle.y - this.y;
424
  const distToObstacle = Math.sqrt(dx * dx + dy * dy);
425
+ const angleToObstacle = Math.atan2(dy, dx);
426
+
427
+ let angleDiff = Math.abs(angle - angleToObstacle);
428
+ if (angleDiff > Math.PI) angleDiff = 2 * Math.PI - angleDiff;
429
 
430
+ if (angleDiff < 0.5 && distToObstacle < distance) {
431
+ distance = Math.max(0, distToObstacle - obstacle.size);
 
 
 
 
 
 
 
 
 
 
 
432
  }
433
  }
434
 
435
+ // Check boundaries
436
+ const cos = Math.cos(angle);
437
+ const sin = Math.sin(angle);
438
+
439
+ if (cos > 0) distance = Math.min(distance, (canvas.width - this.x) / cos);
440
+ else if (cos < 0) distance = Math.min(distance, -this.x / cos);
441
+
442
+ if (sin > 0) distance = Math.min(distance, (canvas.height - this.y) / sin);
443
+ else if (sin < 0) distance = Math.min(distance, -this.y / sin);
444
+
445
+ distance = Math.max(0, distance - 10);
446
 
447
  this.sensors.push({
448
  angle: angle,
449
  distance: distance,
450
  x: this.x + Math.cos(angle) * distance,
451
+ y: this.y + Math.sin(angle) * distance
 
452
  });
453
  }
454
  }
455
 
456
+ makeDecision() {
457
+ decisionCount++;
458
+ let decision = 'Exploring';
459
 
460
+ // Find closest target
461
+ let closestTarget = null;
462
+ let minTargetDist = Infinity;
463
 
464
+ for (let target of targets) {
465
+ const dist = Math.sqrt((target.x - this.x) ** 2 + (target.y - this.y) ** 2);
466
+ if (dist < minTargetDist) {
467
+ minTargetDist = dist;
468
+ closestTarget = target;
469
+ }
470
+ }
471
 
472
+ // Calculate avoidance
473
+ let avoidX = 0, avoidY = 0;
474
+ let hasObstacle = false;
475
+
476
+ for (let sensor of this.sensors) {
477
+ if (sensor.distance < this.sensorRange * 0.6) {
478
+ hasObstacle = true;
479
+ const strength = (this.sensorRange * 0.6 - sensor.distance) / (this.sensorRange * 0.6);
480
+ avoidX -= Math.cos(sensor.angle) * strength;
481
+ avoidY -= Math.sin(sensor.angle) * strength;
482
+ }
483
  }
484
 
485
+ // Apply forces
486
+ if (hasObstacle) {
487
+ decision = 'Avoiding obstacle';
488
+ this.vx += avoidX * 0.5;
489
+ this.vy += avoidY * 0.5;
490
+ stats.obstaclesAvoided++;
491
+ } else if (closestTarget && minTargetDist < 300) {
492
+ decision = `Pursuing target (${Math.round(minTargetDist)}px away)`;
493
+ const dx = closestTarget.x - this.x;
494
+ const dy = closestTarget.y - this.y;
495
+ const dist = Math.sqrt(dx * dx + dy * dy);
496
+
497
+ if (dist > 0) {
498
+ this.vx += (dx / dist) * 0.2;
499
+ this.vy += (dy / dist) * 0.2;
500
+ }
501
+ } else {
502
+ decision = 'Wandering and exploring';
503
+ this.wanderAngle += (Math.random() - 0.5) * 0.3;
504
+ this.vx += Math.cos(this.wanderAngle) * 0.1;
505
+ this.vy += Math.sin(this.wanderAngle) * 0.1;
506
  }
507
 
508
+ document.getElementById('currentDecision').textContent = decision;
509
+ return decision;
510
+ }
511
+
512
+ update() {
513
+ this.speed = parseFloat(document.getElementById('speedSlider').value);
514
+ this.sensorRange = parseInt(document.getElementById('sensorRange').value);
515
+
516
+ this.updateSensors();
517
+ this.makeDecision();
518
+
519
+ // Limit velocity
520
+ const vel = Math.sqrt(this.vx * this.vx + this.vy * this.vy);
521
+ if (vel > this.speed) {
522
+ this.vx = (this.vx / vel) * this.speed;
523
+ this.vy = (this.vy / vel) * this.speed;
524
+ }
525
+
526
+ // Update position
527
+ this.lastX = this.x;
528
+ this.lastY = this.y;
529
+ this.x += this.vx;
530
+ this.y += this.vy;
531
+
532
+ // Boundary collision
533
+ if (this.x < this.size) {
534
+ this.x = this.size;
535
+ this.vx = Math.abs(this.vx);
536
+ }
537
+ if (this.x > canvas.width - this.size) {
538
+ this.x = canvas.width - this.size;
539
+ this.vx = -Math.abs(this.vx);
540
+ }
541
+ if (this.y < this.size) {
542
+ this.y = this.size;
543
+ this.vy = Math.abs(this.vy);
544
+ }
545
+ if (this.y > canvas.height - this.size) {
546
+ this.y = canvas.height - this.size;
547
+ this.vy = -Math.abs(this.vy);
548
+ }
549
+
550
+ // Update stats
551
+ const distance = Math.sqrt((this.x - this.lastX) ** 2 + (this.y - this.lastY) ** 2);
552
+ stats.distanceTraveled += distance;
553
+
554
+ // Check target collisions
555
+ targets = targets.filter(target => {
556
+ const dist = Math.sqrt((target.x - this.x) ** 2 + (target.y - this.y) ** 2);
557
+ if (dist < this.size + target.size) {
558
+ stats.targetsReached++;
559
+ return false;
560
+ }
561
+ return true;
562
+ });
563
+
564
+ // Apply friction
565
+ this.vx *= 0.98;
566
+ this.vy *= 0.98;
567
+ }
568
+
569
+ draw() {
570
+ // Draw sensors
571
+ ctx.strokeStyle = 'rgba(255, 193, 7, 0.3)';
572
+ ctx.lineWidth = 1;
573
+ for (let sensor of this.sensors) {
574
+ ctx.beginPath();
575
+ ctx.moveTo(this.x, this.y);
576
+ ctx.lineTo(sensor.x, sensor.y);
577
+ ctx.stroke();
578
+ }
579
+
580
+ // Draw vehicle
581
+ ctx.fillStyle = '#4CAF50';
582
+ ctx.beginPath();
583
+ ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
584
+ ctx.fill();
585
+
586
+ // Draw direction indicator
587
+ ctx.strokeStyle = '#ffffff';
588
+ ctx.lineWidth = 3;
589
+ ctx.beginPath();
590
+ ctx.moveTo(this.x, this.y);
591
+ ctx.lineTo(this.x + this.vx * 5, this.y + this.vy * 5);
592
+ ctx.stroke();
593
+ }
594
+ }
595
+
596
+ // Obstacle class
597
+ class Obstacle {
598
+ constructor(x, y, size = 20) {
599
+ this.x = x;
600
+ this.y = y;
601
+ this.size = size;
602
+ }
603
+
604
+ draw() {
605
+ ctx.fillStyle = '#f44336';
606
+ ctx.beginPath();
607
+ ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
608
+ ctx.fill();
609
+ }
610
+ }
611
+
612
+ // Target class
613
+ class Target {
614
+ constructor(x, y, size = 15) {
615
+ this.x = x;
616
+ this.y = y;
617
+ this.size = size;
618
+ this.pulse = 0;
619
+ }
620
+
621
+ update() {
622
+ this.pulse += 0.1;
623
+ }
624
+
625
+ draw() {
626
+ const alpha = 0.5 + 0.3 * Math.sin(this.pulse);
627
+ ctx.fillStyle = `rgba(33, 150, 243, ${alpha})`;
628
+ ctx.beginPath();
629
+ ctx.arc(this.x, this.y, this.size + 3 * Math.sin(this.pulse), 0, Math.PI * 2);
630
+ ctx.fill();
631
  }
632
  }
633
+
634
+ // Animation loop
635
+ function animate() {
636
+ if (!isRunning) return;
637
+
638
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
639
+
640
+ // Update and draw vehicle
641
+ if (vehicle) {
642
+ vehicle.update();
643
+ vehicle.draw();
644
+ }
645
+
646
+ // Update and draw targets
647
+ targets.forEach(target => {
648
+ target.update();
649
+ target.draw();
650
+ });
651
+
652
+ // Draw obstacles
653
+ obstacles.forEach(obstacle => obstacle.draw());
654
+
655
+ // Update UI stats
656
+ updateStats();
657
+
658
+ animationId = requestAnimationFrame(animate);
659
+ }
660
+
661
+ function updateStats() {
662
+ document.getElementById('distanceTraveled').textContent = Math.round(stats.distanceTraveled) + 'm';
663
+ document.getElementById('targetsReached').textContent = stats.targetsReached;
664
+ document.getElementById('obstaclesAvoided').textContent = stats.obstaclesAvoided;
665
+
666
+ // Calculate decisions per second
667
+ const now = Date.now();
668
+ if (now - lastDecisionTime >= 1000) {
669
+ stats.decisionsPerSecond = decisionCount;
670
+ document.getElementById('decisionsPerSec').textContent = stats.decisionsPerSecond;
671
+ decisionCount = 0;
672
+ lastDecisionTime = now;
673
+ }
674
+ }
675
+
676
+ // Initialize simulation
677
+ function initSimulation() {
678
+ vehicle = new AutonomousVehicle(100, 100);
679
+
680
+ // Add some initial obstacles and targets
681
+ obstacles.push(new Obstacle(300, 200, 25));
682
+ obstacles.push(new Obstacle(500, 400, 30));
683
+ targets.push(new Target(600, 150));
684
+ targets.push(new Target(200, 400));
685
+
686
+ document.getElementById('currentDecision').textContent = 'Ready - Click Start!';
687
+ }
688
+
689
+ // Control functions
690
+ function startSimulation() {
691
+ if (!vehicle) initSimulation();
692
+ isRunning = true;
693
+ document.getElementById('startBtn').disabled = true;
694
+ document.getElementById('pauseBtn').disabled = false;
695
+ animate();
696
+ }
697
+
698
+ function pauseSimulation() {
699
+ isRunning = false;
700
+ document.getElementById('startBtn').disabled = false;
701
+ document.getElementById('pauseBtn').disabled = true;
702
+ if (animationId) {
703
+ cancelAnimationFrame(animationId);
704
+ }
705
+ }
706
+
707
+ function resetSimulation() {
708
+ isRunning = false;
709
+ if (animationId) {
710
+ cancelAnimationFrame(animationId);
711
+ }
712
+
713
+ obstacles = [];
714
+ targets = [];
715
+ stats = { distanceTraveled: 0, targetsReached: 0, obstaclesAvoided: 0, decisionsPerSecond: 0 };
716
+ decisionCount = 0;
717
+
718
+ document.getElementById('startBtn').disabled = false;
719
+ document.getElementById('pauseBtn').disabled = true;
720
+
721
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
722
+ initSimulation();
723
+ }
724
+
725
+ // Event listeners
726
+ document.getElementById('startBtn').addEventListener('click', startSimulation);
727
+ document.getElementById('pauseBtn').addEventListener('click', pauseSimulation);
728
+ document.getElementById('resetBtn').addEventListener('click', resetSimulation);
729
+
730
+ document.getElementById('addObstacleBtn').addEventListener('click', () => {
731
+ const x = Math.random() * (canvas.width - 100) + 50;
732
+ const y = Math.random() * (canvas.height - 100) + 50;
733
+ obstacles.push(new Obstacle(x, y, 20 + Math.random() * 20));
734
+ });
735
+
736
+ document.getElementById('addTargetBtn').addEventListener('click', () => {
737
+ const x = Math.random() * (canvas.width - 100) + 50;
738
+ const y = Math.random() * (canvas.height - 100) + 50;
739
+ targets.push(new Target(x, y));
740
+ });
741
+
742
+ document.getElementById('clearBtn').addEventListener('click', () => {
743
+ obstacles = [];
744
+ targets = [];
745
+ });
746
+
747
+ // Canvas click events
748
+ canvas.addEventListener('click', (e) => {
749
+ const rect = canvas.getBoundingClientRect();
750
+ const x = e.clientX - rect.left;
751
+ const y = e.clientY - rect.top;
752
+
753
+ if (e.shiftKey) {
754
+ obstacles.push(new Obstacle(x, y));
755
+ } else {
756
+ targets.push(new Target(x, y));
757
+ }
758
+ });
759
+
760
+ // Slider updates
761
+ document.getElementById('speedSlider').addEventListener('input', (e) => {
762
+ document.getElementById('speedValue').textContent = e.target.value;
763
+ });
764
+
765
+ document.getElementById('sensorRange').addEventListener('input', (e) => {
766
+ document.getElementById('sensorValue').textContent = e.target.value;
767
+ });
768
+
769
+ // Initialize on load
770
+ initSimulation();
771
+ </script>
772
+ </body>
773
+ </html>