docto41 commited on
Commit
48e519e
·
verified ·
1 Parent(s): 36ad2f9

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +483 -83
  2. prompts.txt +2 -1
index.html CHANGED
@@ -3,10 +3,14 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Simulateur de Conduite de Camion - Vue Panoramique</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
 
 
 
 
10
  .dashboard {
11
  background: linear-gradient(135deg, #2c3e50 0%, #1a1a2e 100%);
12
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
@@ -35,6 +39,34 @@
35
  transform-origin: center 70%;
36
  transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
37
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  .environment-selector {
39
  scrollbar-width: thin;
40
  scrollbar-color: #4a5568 #2d3748;
@@ -54,12 +86,12 @@
54
  <body class="bg-gray-900 text-white min-h-screen flex flex-col items-center justify-center p-4">
55
  <div class="w-full max-w-6xl">
56
  <h1 class="text-3xl md:text-4xl font-bold text-center mb-6 text-blue-300">
57
- <i class="fas fa-truck mr-3"></i> Simulateur de Conduite de Camion
58
  </h1>
59
 
60
  <div class="relative mb-8">
61
- <!-- Vue panoramique principale -->
62
- <div class="panoramic-view w-full h-96 md:h-[500px] bg-gray-800 rounded-xl overflow-hidden relative">
63
  <div id="main-view" class="w-full h-full bg-cover bg-center transition-all duration-1000" style="background-image: url('https://images.unsplash.com/photo-1509316785289-025f5b8b4dd2?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2076&q=80');">
64
  <div class="absolute inset-0 bg-black bg-opacity-30 flex items-center justify-center">
65
  <p class="text-xl md:text-2xl font-semibold text-white bg-black bg-opacity-50 px-4 py-2 rounded-lg">
@@ -76,37 +108,35 @@
76
  <div class="w-full h-full bg-cover bg-center opacity-90" id="right-mirror"></div>
77
  </div>
78
 
79
- <!-- Vue du dessous (optionnelle) -->
80
- <div class="absolute bottom-2 left-1/2 transform -translate-x-1/2 w-32 h-16 bg-gray-700 rounded-b-lg overflow-hidden opacity-80">
81
- <div class="w-full h-full bg-gray-800" id="under-view"></div>
82
- </div>
83
  </div>
84
 
85
  <!-- Sélecteur d'environnement -->
86
  <div class="environment-selector mt-4 flex overflow-x-auto pb-2 gap-2">
87
- <button onclick="changeEnvironment('montagne', 'https://images.unsplash.com/photo-1519681393784-d120267933ba?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
88
  <i class="fas fa-mountain mr-2"></i> Montagne
89
  </button>
90
- <button onclick="changeEnvironment('autoroute', 'https://images.unsplash.com/photo-1544620347-c4fd4a3d5957?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2069&q=80')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
91
  <i class="fas fa-road mr-2"></i> Autoroute
92
  </button>
93
- <button onclick="changeEnvironment('ville', 'https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2144&q=80')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
94
  <i class="fas fa-city mr-2"></i> Ville
95
  </button>
96
- <button onclick="changeEnvironment('campagne', 'https://images.unsplash.com/photo-1500382014318-4737b1f0f59a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
97
  <i class="fas fa-tractor mr-2"></i> Campagne
98
  </button>
99
- <button onclick="changeEnvironment('désert', 'https://images.unsplash.com/photo-1509316785289-025f5b8b4dd2?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2076&q=80')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
100
  <i class="fas fa-sun mr-2"></i> Désert
101
  </button>
102
- <button onclick="changeEnvironment('neige', 'https://images.unsplash.com/photo-1483728642387-6c3bdd6c93e5?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2076&q=80')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
103
  <i class="fas fa-snowflake mr-2"></i> Neige
104
  </button>
105
  </div>
106
  </div>
107
 
108
- <!-- Tableau de bord -->
109
- <div class="dashboard p-6 rounded-2xl mb-6">
110
  <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
111
  <!-- Compteur de vitesse -->
112
  <div class="bg-gray-800 bg-opacity-50 p-4 rounded-xl flex flex-col items-center">
@@ -123,7 +153,7 @@
123
  <div class="mt-2 text-sm text-gray-400">km/h</div>
124
  </div>
125
 
126
- <!-- Volant et commandes -->
127
  <div class="flex flex-col items-center justify-center">
128
  <div class="steering-wheel relative w-24 h-24 md:w-32 md:h-32 bg-gray-700 rounded-full border-4 border-gray-600 mb-4 flex items-center justify-center cursor-grab active:cursor-grabbing" id="steering-wheel">
129
  <div class="w-6 h-6 md:w-8 md:h-8 bg-gray-600 rounded-full"></div>
@@ -140,7 +170,7 @@
140
  </div>
141
  </div>
142
 
143
- <!-- Autres indicateurs -->
144
  <div class="bg-gray-800 bg-opacity-50 p-4 rounded-xl">
145
  <h3 class="text-lg font-semibold mb-3 text-blue-200"><i class="fas fa-info-circle mr-2"></i> Informations</h3>
146
  <div class="space-y-3">
@@ -162,36 +192,45 @@
162
  <span class="text-gray-400"><i class="fas fa-road mr-2"></i> Distance:</span>
163
  <span class="font-mono" id="distance-display">0 km</span>
164
  </div>
 
 
 
 
165
  </div>
166
  </div>
167
  </div>
168
  </div>
169
 
170
- <!-- Contrôles supplémentaires -->
171
  <div class="grid grid-cols-2 md:grid-cols-4 gap-3 mb-6">
172
- <button class="bg-gray-800 hover:bg-gray-700 px-4 py-3 rounded-lg flex items-center justify-center" id="lights-btn">
173
  <i class="fas fa-lightbulb mr-2"></i> Phares
174
  </button>
175
- <button class="bg-gray-800 hover:bg-gray-700 px-4 py-3 rounded-lg flex items-center justify-center" id="horn-btn">
176
  <i class="fas fa-bullhorn mr-2"></i> Klaxon
177
  </button>
178
- <button class="bg-gray-800 hover:bg-gray-700 px-4 py-3 rounded-lg flex items-center justify-center" id="gear-up">
179
  <i class="fas fa-arrow-up mr-2"></i> Monter vitesse
180
  </button>
181
- <button class="bg-gray-800 hover:bg-gray-700 px-4 py-3 rounded-lg flex items-center justify-center" id="gear-down">
182
  <i class="fas fa-arrow-down mr-2"></i> Descendre vitesse
183
  </button>
184
  </div>
185
 
186
- <!-- Affichage de la vitesse actuelle -->
187
  <div class="text-center mb-4">
188
- <div class="text-5xl font-bold text-blue-300" id="big-speed-display">0</div>
189
  <div class="text-gray-400">km/h</div>
190
  </div>
 
 
 
 
 
191
  </div>
192
 
193
  <script>
194
- // Variables d'état
195
  let speed = 0;
196
  let isAccelerating = false;
197
  let isBraking = false;
@@ -201,6 +240,11 @@
201
  let distance = 0;
202
  let gear = 1;
203
  let lightsOn = false;
 
 
 
 
 
204
 
205
  // Éléments DOM
206
  const speedDisplay = document.getElementById('speed-display');
@@ -212,7 +256,7 @@
212
  const mainView = document.getElementById('main-view');
213
  const leftMirror = document.getElementById('left-mirror');
214
  const rightMirror = document.getElementById('right-mirror');
215
- const underView = document.getElementById('under-view');
216
  const fuelLevel = document.getElementById('fuel-level');
217
  const rpmDisplay = document.getElementById('rpm-display');
218
  const distanceDisplay = document.getElementById('distance-display');
@@ -220,19 +264,31 @@
220
  const hornBtn = document.getElementById('horn-btn');
221
  const gearUpBtn = document.getElementById('gear-up');
222
  const gearDownBtn = document.getElementById('gear-down');
 
 
 
 
223
 
224
- // Sons
225
- const hornSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-car-horn-718.mp3');
226
- const engineSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-truck-engine-starting-1109.mp3');
227
  engineSound.loop = true;
 
 
 
 
 
 
228
 
229
- // Gestionnaire d'événements pour le volant
230
  let isSteering = false;
231
  let startX = 0;
232
 
233
  steeringWheel.addEventListener('mousedown', (e) => {
234
  isSteering = true;
235
  startX = e.clientX;
 
 
236
  });
237
 
238
  document.addEventListener('mousemove', (e) => {
@@ -242,38 +298,58 @@
242
  steeringWheel.style.transform = `rotate(${steeringAngle}deg)`;
243
 
244
  // Ajuster la vue panoramique en fonction de l'angle du volant
245
- const panoramicView = document.querySelector('.panoramic-view');
246
- panoramicView.style.transform = `rotateY(${steeringAngle / 10}deg)`;
247
 
248
  // Mettre à jour les rétroviseurs
249
  updateMirrors();
 
 
 
 
 
 
250
  }
251
  });
252
 
253
  document.addEventListener('mouseup', () => {
254
- isSteering = false;
255
- // Retour progressif à la position neutre
256
- const returnToCenter = () => {
257
- if (Math.abs(steeringAngle) > 1) {
258
- steeringAngle *= 0.9;
259
- steeringWheel.style.transform = `rotate(${steeringAngle}deg)`;
260
- document.querySelector('.panoramic-view').style.transform = `rotateY(${steeringAngle / 10}deg)`;
261
- updateMirrors();
262
- requestAnimationFrame(returnToCenter);
263
- } else {
264
- steeringAngle = 0;
265
- steeringWheel.style.transform = 'rotate(0deg)';
266
- document.querySelector('.panoramic-view').style.transform = 'rotateY(0deg)';
267
- updateMirrors();
268
- }
269
- };
270
- returnToCenter();
 
 
 
 
 
 
 
 
 
 
271
  });
272
 
273
- // Gestion des pédales
274
  gasPedal.addEventListener('mousedown', () => {
275
  isAccelerating = true;
276
- if (speed < 5) engineSound.play();
 
 
 
 
 
277
  });
278
 
279
  gasPedal.addEventListener('mouseup', () => {
@@ -282,45 +358,130 @@
282
 
283
  brakePedal.addEventListener('mousedown', () => {
284
  isBraking = true;
 
 
 
 
 
 
 
 
 
285
  });
286
 
287
  brakePedal.addEventListener('mouseup', () => {
288
  isBraking = false;
289
  });
290
 
291
- // Gestion des autres contrôles
 
 
 
 
 
 
 
 
 
 
 
292
  lightsBtn.addEventListener('click', () => {
293
  lightsOn = !lightsOn;
294
  lightsBtn.innerHTML = lightsOn ?
295
  '<i class="fas fa-lightbulb mr-2 text-yellow-300"></i> Phares (ON)' :
296
  '<i class="fas fa-lightbulb mr-2"></i> Phares';
 
297
  });
298
 
299
  hornBtn.addEventListener('click', () => {
300
  hornSound.currentTime = 0;
301
  hornSound.play();
 
 
302
  });
303
 
304
  gearUpBtn.addEventListener('click', () => {
305
- if (gear < 10) gear++;
306
- updateGearDisplay();
 
 
 
 
 
 
 
 
 
 
 
 
307
  });
308
 
309
  gearDownBtn.addEventListener('click', () => {
310
- if (gear > 1) gear--;
311
- updateGearDisplay();
 
 
 
 
 
 
312
  });
313
 
314
- function updateGearDisplay() {
315
- rpmDisplay.textContent = Math.floor(800 + (speed * 20 / gear));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
  }
317
 
318
- // Mise à jour des rétroviseurs
319
  function updateMirrors() {
320
  if (!currentEnvironment) return;
321
 
322
- // Simuler une vue différente dans les rétroviseurs
323
  const mirrorOffset = steeringAngle * 2;
 
324
 
325
  // Rétroviseur gauche
326
  leftMirror.style.backgroundImage = mainView.style.backgroundImage;
@@ -331,13 +492,24 @@
331
  rightMirror.style.backgroundImage = mainView.style.backgroundImage;
332
  rightMirror.style.backgroundPositionX = `${50 + mirrorOffset}%`;
333
 
334
- // Vue du dessous (simplifiée)
335
- underView.style.background = `linear-gradient(90deg, #333, #555, #333)`;
 
 
 
 
 
 
 
336
  }
337
 
338
- // Changer d'environnement
339
- function changeEnvironment(env, imgUrl) {
340
  currentEnvironment = env;
 
 
 
 
341
  mainView.style.backgroundImage = `url('${imgUrl}')`;
342
 
343
  // Mettre à jour les rétroviseurs
@@ -347,6 +519,121 @@
347
  speed = 0;
348
  updateSpeedDisplay();
349
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  // Jouer un son d'ambiance différent selon l'environnement
351
  const ambientSound = new Audio();
352
  switch(env) {
@@ -374,7 +661,7 @@
374
  ambientSound.play();
375
  }
376
 
377
- // Mise à jour de l'affichage de la vitesse
378
  function updateSpeedDisplay() {
379
  speedDisplay.textContent = Math.floor(speed);
380
  bigSpeedDisplay.textContent = Math.floor(speed);
@@ -389,21 +676,67 @@
389
  arc.setAttribute('d', describeArc(50, 50, 35, 0, arcAngle));
390
 
391
  // Mettre à jour le RPM
392
- rpmDisplay.textContent = Math.floor(800 + (speed * 20 / gear));
 
 
 
 
 
 
 
 
 
 
 
 
393
 
394
  // Mettre à jour la distance parcourue
395
- distance += speed / 3600; // Ajouter la distance en km (vitesse en km/h, 1 heure = 3600 secondes)
396
  distanceDisplay.textContent = distance.toFixed(2);
397
 
398
  // Mettre à jour le niveau de carburant
399
- fuel = Math.max(0, fuel - (speed / 5000));
400
  fuelLevel.style.width = `${fuel}%`;
401
- if (fuel < 20) fuelLevel.classList.add('bg-red-500');
402
- else fuelLevel.classList.remove('bg-red-500');
 
 
 
 
 
 
 
 
 
 
403
 
404
  // Ajuster le son du moteur
405
  engineSound.volume = 0.3 + (speed / 140) * 0.7;
406
  engineSound.playbackRate = 0.8 + (speed / 140) * 0.8;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
407
  }
408
 
409
  // Fonction pour décrire un arc en SVG
@@ -422,15 +755,47 @@
422
  };
423
  }
424
 
425
- // Boucle de simulation
426
  function simulate() {
427
  if (isAccelerating && fuel > 0) {
428
- speed = Math.min(140, speed + 0.2 * gear);
 
 
 
 
 
 
 
 
 
 
429
  } else if (isBraking) {
430
- speed = Math.max(0, speed - 0.5);
 
 
 
 
 
 
 
 
 
431
  } else {
432
  // Ralentissement naturel
433
- speed = Math.max(0, speed - 0.05);
 
 
 
 
 
 
 
 
 
 
 
 
 
434
  }
435
 
436
  updateSpeedDisplay();
@@ -440,45 +805,71 @@
440
  // Démarrer la simulation
441
  simulate();
442
 
443
- // Gestion du clavier
444
  document.addEventListener('keydown', (e) => {
445
  switch(e.key) {
446
  case 'ArrowUp':
447
  isAccelerating = true;
448
- if (speed < 5) engineSound.play();
 
 
 
 
449
  break;
450
  case 'ArrowDown':
451
  isBraking = true;
 
 
 
452
  break;
453
  case 'ArrowLeft':
454
  steeringAngle = Math.max(-90, steeringAngle - 5);
455
  steeringWheel.style.transform = `rotate(${steeringAngle}deg)`;
456
- document.querySelector('.panoramic-view').style.transform = `rotateY(${steeringAngle / 10}deg)`;
457
  updateMirrors();
 
 
 
458
  break;
459
  case 'ArrowRight':
460
  steeringAngle = Math.min(90, steeringAngle + 5);
461
  steeringWheel.style.transform = `rotate(${steeringAngle}deg)`;
462
- document.querySelector('.panoramic-view').style.transform = `rotateY(${steeringAngle / 10}deg)`;
463
  updateMirrors();
 
 
 
464
  break;
465
  case ' ':
466
  hornSound.currentTime = 0;
467
  hornSound.play();
 
468
  break;
469
  case 'l':
 
470
  lightsOn = !lightsOn;
471
  lightsBtn.innerHTML = lightsOn ?
472
  '<i class="fas fa-lightbulb mr-2 text-yellow-300"></i> Phares (ON)' :
473
  '<i class="fas fa-lightbulb mr-2"></i> Phares';
 
474
  break;
475
  case '+':
476
- if (gear < 10) gear++;
477
- updateGearDisplay();
 
 
 
 
 
478
  break;
479
  case '-':
480
- if (gear > 1) gear--;
481
- updateGearDisplay();
 
 
 
 
 
482
  break;
483
  }
484
  });
@@ -493,6 +884,15 @@
493
  break;
494
  }
495
  });
 
 
 
 
 
 
 
 
 
496
  </script>
497
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=docto41/simulator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
498
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Simulateur de Camion - Expérience Réaliste</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
+ body {
11
+ overflow-x: hidden;
12
+ touch-action: manipulation;
13
+ }
14
  .dashboard {
15
  background: linear-gradient(135deg, #2c3e50 0%, #1a1a2e 100%);
16
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
 
39
  transform-origin: center 70%;
40
  transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
41
  }
42
+ .vibration-effect {
43
+ animation: vibration 0.3s infinite;
44
+ }
45
+ .road-bump {
46
+ animation: bump 0.5s ease-out;
47
+ }
48
+ .engine-shake {
49
+ animation: shake 0.2s infinite;
50
+ }
51
+
52
+ @keyframes vibration {
53
+ 0%, 100% { transform: translate(0, 0); }
54
+ 25% { transform: translate(-1px, -1px); }
55
+ 50% { transform: translate(1px, 1px); }
56
+ 75% { transform: translate(1px, -1px); }
57
+ }
58
+
59
+ @keyframes bump {
60
+ 0%, 100% { transform: translateY(0); }
61
+ 50% { transform: translateY(-10px); }
62
+ }
63
+
64
+ @keyframes shake {
65
+ 0%, 100% { transform: translateX(0); }
66
+ 25% { transform: translateX(-2px); }
67
+ 75% { transform: translateX(2px); }
68
+ }
69
+
70
  .environment-selector {
71
  scrollbar-width: thin;
72
  scrollbar-color: #4a5568 #2d3748;
 
86
  <body class="bg-gray-900 text-white min-h-screen flex flex-col items-center justify-center p-4">
87
  <div class="w-full max-w-6xl">
88
  <h1 class="text-3xl md:text-4xl font-bold text-center mb-6 text-blue-300">
89
+ <i class="fas fa-truck mr-3"></i> Simulateur de Camion - Expérience Réaliste
90
  </h1>
91
 
92
  <div class="relative mb-8">
93
+ <!-- Vue panoramique principale avec effets -->
94
+ <div id="panoramic-container" class="panoramic-view w-full h-96 md:h-[500px] bg-gray-800 rounded-xl overflow-hidden relative">
95
  <div id="main-view" class="w-full h-full bg-cover bg-center transition-all duration-1000" style="background-image: url('https://images.unsplash.com/photo-1509316785289-025f5b8b4dd2?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2076&q=80');">
96
  <div class="absolute inset-0 bg-black bg-opacity-30 flex items-center justify-center">
97
  <p class="text-xl md:text-2xl font-semibold text-white bg-black bg-opacity-50 px-4 py-2 rounded-lg">
 
108
  <div class="w-full h-full bg-cover bg-center opacity-90" id="right-mirror"></div>
109
  </div>
110
 
111
+ <!-- Effet de pluie/vibration -->
112
+ <div id="weather-effects" class="absolute inset-0 pointer-events-none"></div>
 
 
113
  </div>
114
 
115
  <!-- Sélecteur d'environnement -->
116
  <div class="environment-selector mt-4 flex overflow-x-auto pb-2 gap-2">
117
+ <button onclick="changeEnvironment('montagne', 'https://images.unsplash.com/photo-1519681393784-d120267933ba?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80', 'pluie')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
118
  <i class="fas fa-mountain mr-2"></i> Montagne
119
  </button>
120
+ <button onclick="changeEnvironment('autoroute', 'https://images.unsplash.com/photo-1544620347-c4fd4a3d5957?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2069&q=80', 'sec')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
121
  <i class="fas fa-road mr-2"></i> Autoroute
122
  </button>
123
+ <button onclick="changeEnvironment('ville', 'https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2144&q=80', 'pluie')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
124
  <i class="fas fa-city mr-2"></i> Ville
125
  </button>
126
+ <button onclick="changeEnvironment('campagne', 'https://images.unsplash.com/photo-1500382014318-4737b1f0f59a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80', 'sec')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
127
  <i class="fas fa-tractor mr-2"></i> Campagne
128
  </button>
129
+ <button onclick="changeEnvironment('désert', 'https://images.unsplash.com/photo-1509316785289-025f5b8b4dd2?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2076&q=80', 'sable')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
130
  <i class="fas fa-sun mr-2"></i> Désert
131
  </button>
132
+ <button onclick="changeEnvironment('neige', 'https://images.unsplash.com/photo-1483728642387-6c3bdd6c93e5?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2076&q=80', 'neige')" class="flex-shrink-0 bg-gray-800 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
133
  <i class="fas fa-snowflake mr-2"></i> Neige
134
  </button>
135
  </div>
136
  </div>
137
 
138
+ <!-- Tableau de bord avec effets de vibration -->
139
+ <div id="dashboard" class="dashboard p-6 rounded-2xl mb-6">
140
  <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
141
  <!-- Compteur de vitesse -->
142
  <div class="bg-gray-800 bg-opacity-50 p-4 rounded-xl flex flex-col items-center">
 
153
  <div class="mt-2 text-sm text-gray-400">km/h</div>
154
  </div>
155
 
156
+ <!-- Volant et commandes avec retour de force -->
157
  <div class="flex flex-col items-center justify-center">
158
  <div class="steering-wheel relative w-24 h-24 md:w-32 md:h-32 bg-gray-700 rounded-full border-4 border-gray-600 mb-4 flex items-center justify-center cursor-grab active:cursor-grabbing" id="steering-wheel">
159
  <div class="w-6 h-6 md:w-8 md:h-8 bg-gray-600 rounded-full"></div>
 
170
  </div>
171
  </div>
172
 
173
+ <!-- Autres indicateurs avec effets -->
174
  <div class="bg-gray-800 bg-opacity-50 p-4 rounded-xl">
175
  <h3 class="text-lg font-semibold mb-3 text-blue-200"><i class="fas fa-info-circle mr-2"></i> Informations</h3>
176
  <div class="space-y-3">
 
192
  <span class="text-gray-400"><i class="fas fa-road mr-2"></i> Distance:</span>
193
  <span class="font-mono" id="distance-display">0 km</span>
194
  </div>
195
+ <div class="flex justify-between">
196
+ <span class="text-gray-400"><i class="fas fa-road mr-2"></i> Suspension:</span>
197
+ <span class="font-mono" id="suspension-display">Normale</span>
198
+ </div>
199
  </div>
200
  </div>
201
  </div>
202
  </div>
203
 
204
+ <!-- Contrôles supplémentaires avec effets haptiques -->
205
  <div class="grid grid-cols-2 md:grid-cols-4 gap-3 mb-6">
206
+ <button class="bg-gray-800 hover:bg-gray-700 px-4 py-3 rounded-lg flex items-center justify-center haptic-btn" id="lights-btn">
207
  <i class="fas fa-lightbulb mr-2"></i> Phares
208
  </button>
209
+ <button class="bg-gray-800 hover:bg-gray-700 px-4 py-3 rounded-lg flex items-center justify-center haptic-btn" id="horn-btn">
210
  <i class="fas fa-bullhorn mr-2"></i> Klaxon
211
  </button>
212
+ <button class="bg-gray-800 hover:bg-gray-700 px-4 py-3 rounded-lg flex items-center justify-center haptic-btn" id="gear-up">
213
  <i class="fas fa-arrow-up mr-2"></i> Monter vitesse
214
  </button>
215
+ <button class="bg-gray-800 hover:bg-gray-700 px-4 py-3 rounded-lg flex items-center justify-center haptic-btn" id="gear-down">
216
  <i class="fas fa-arrow-down mr-2"></i> Descendre vitesse
217
  </button>
218
  </div>
219
 
220
+ <!-- Affichage de la vitesse actuelle avec effet de vibration -->
221
  <div class="text-center mb-4">
222
+ <div class="text-5xl font-bold text-blue-300 vibration-text" id="big-speed-display">0</div>
223
  <div class="text-gray-400">km/h</div>
224
  </div>
225
+
226
+ <!-- Indicateur de vibration -->
227
+ <div class="w-full bg-gray-800 h-2 rounded-full overflow-hidden mb-4">
228
+ <div id="vibration-indicator" class="bg-blue-500 h-full" style="width: 0%"></div>
229
+ </div>
230
  </div>
231
 
232
  <script>
233
+ // Variables d'état améliorées
234
  let speed = 0;
235
  let isAccelerating = false;
236
  let isBraking = false;
 
240
  let distance = 0;
241
  let gear = 1;
242
  let lightsOn = false;
243
+ let vibrationIntensity = 0;
244
+ let roadCondition = 'normal';
245
+ let lastBumpTime = 0;
246
+ let engineHealth = 100;
247
+ let suspensionStatus = 'normal';
248
 
249
  // Éléments DOM
250
  const speedDisplay = document.getElementById('speed-display');
 
256
  const mainView = document.getElementById('main-view');
257
  const leftMirror = document.getElementById('left-mirror');
258
  const rightMirror = document.getElementById('right-mirror');
259
+ const weatherEffects = document.getElementById('weather-effects');
260
  const fuelLevel = document.getElementById('fuel-level');
261
  const rpmDisplay = document.getElementById('rpm-display');
262
  const distanceDisplay = document.getElementById('distance-display');
 
264
  const hornBtn = document.getElementById('horn-btn');
265
  const gearUpBtn = document.getElementById('gear-up');
266
  const gearDownBtn = document.getElementById('gear-down');
267
+ const panoramicContainer = document.getElementById('panoramic-container');
268
+ const dashboard = document.getElementById('dashboard');
269
+ const vibrationIndicator = document.getElementById('vibration-indicator');
270
+ const suspensionDisplay = document.getElementById('suspension-display');
271
 
272
+ // Sons améliorés
273
+ const hornSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-truck-horn-715.mp3');
274
+ const engineSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-heavy-diesel-truck-engine-1711.mp3');
275
  engineSound.loop = true;
276
+ const bumpSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-car-bump-1070.mp3');
277
+ const rainSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-rain-loop-1243.mp3');
278
+ rainSound.loop = true;
279
+ const windSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-wind-loop-1244.mp3');
280
+ windSound.loop = true;
281
+ const gearSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-gear-shift-in-a-car-1079.mp3');
282
 
283
+ // Gestionnaire d'événements pour le volant avec retour de force
284
  let isSteering = false;
285
  let startX = 0;
286
 
287
  steeringWheel.addEventListener('mousedown', (e) => {
288
  isSteering = true;
289
  startX = e.clientX;
290
+ // Effet de résistance
291
+ steeringWheel.style.transition = 'none';
292
  });
293
 
294
  document.addEventListener('mousemove', (e) => {
 
298
  steeringWheel.style.transform = `rotate(${steeringAngle}deg)`;
299
 
300
  // Ajuster la vue panoramique en fonction de l'angle du volant
301
+ panoramicContainer.style.transform = `rotateY(${steeringAngle / 10}deg)`;
 
302
 
303
  // Mettre à jour les rétroviseurs
304
  updateMirrors();
305
+
306
+ // Effet de vibration en fonction de la vitesse et de l'angle
307
+ if (speed > 30 && Math.abs(steeringAngle) > 30) {
308
+ const intensity = Math.min(1, (speed / 100) * (Math.abs(steeringAngle) / 90));
309
+ applyVibration(intensity * 0.7);
310
+ }
311
  }
312
  });
313
 
314
  document.addEventListener('mouseup', () => {
315
+ if (isSteering) {
316
+ isSteering = false;
317
+ steeringWheel.style.transition = 'transform 0.3s ease';
318
+
319
+ // Retour progressif à la position neutre avec effet de recentrage
320
+ const returnToCenter = () => {
321
+ if (Math.abs(steeringAngle) > 1) {
322
+ steeringAngle *= 0.7; // Plus rapide que précédemment
323
+ steeringWheel.style.transform = `rotate(${steeringAngle}deg)`;
324
+ panoramicContainer.style.transform = `rotateY(${steeringAngle / 10}deg)`;
325
+ updateMirrors();
326
+
327
+ // Petit effet de vibration lors du retour
328
+ if (Math.abs(steeringAngle) < 10 && speed > 20) {
329
+ applyVibration(0.2 * (speed / 100));
330
+ }
331
+
332
+ requestAnimationFrame(returnToCenter);
333
+ } else {
334
+ steeringAngle = 0;
335
+ steeringWheel.style.transform = 'rotate(0deg)';
336
+ panoramicContainer.style.transform = 'rotateY(0deg)';
337
+ updateMirrors();
338
+ }
339
+ };
340
+ returnToCenter();
341
+ }
342
  });
343
 
344
+ // Gestion des pédales avec effets réalistes
345
  gasPedal.addEventListener('mousedown', () => {
346
  isAccelerating = true;
347
+ if (speed < 5) {
348
+ engineSound.currentTime = 0;
349
+ engineSound.play();
350
+ }
351
+ // Petit effet de vibration
352
+ applyVibration(0.1);
353
  });
354
 
355
  gasPedal.addEventListener('mouseup', () => {
 
358
 
359
  brakePedal.addEventListener('mousedown', () => {
360
  isBraking = true;
361
+ // Effet de vibration plus fort lors du freinage
362
+ if (speed > 20) {
363
+ applyVibration(0.3);
364
+ // Effet de freinage brusque
365
+ if (speed > 60) {
366
+ dashboard.classList.add('road-bump');
367
+ setTimeout(() => dashboard.classList.remove('road-bump'), 500);
368
+ }
369
+ }
370
  });
371
 
372
  brakePedal.addEventListener('mouseup', () => {
373
  isBraking = false;
374
  });
375
 
376
+ // Gestion des autres contrôles avec effets haptiques
377
+ const hapticButtons = document.querySelectorAll('.haptic-btn');
378
+ hapticButtons.forEach(btn => {
379
+ btn.addEventListener('mousedown', () => {
380
+ btn.classList.add('active:scale-95');
381
+ applyVibration(0.05);
382
+ });
383
+ btn.addEventListener('mouseup', () => {
384
+ btn.classList.remove('active:scale-95');
385
+ });
386
+ });
387
+
388
  lightsBtn.addEventListener('click', () => {
389
  lightsOn = !lightsOn;
390
  lightsBtn.innerHTML = lightsOn ?
391
  '<i class="fas fa-lightbulb mr-2 text-yellow-300"></i> Phares (ON)' :
392
  '<i class="fas fa-lightbulb mr-2"></i> Phares';
393
+ applyVibration(0.05);
394
  });
395
 
396
  hornBtn.addEventListener('click', () => {
397
  hornSound.currentTime = 0;
398
  hornSound.play();
399
+ // Forte vibration lors du klaxon
400
+ applyVibration(0.4);
401
  });
402
 
403
  gearUpBtn.addEventListener('click', () => {
404
+ if (gear < 10) {
405
+ gear++;
406
+ gearSound.currentTime = 0;
407
+ gearSound.play();
408
+ updateGearDisplay();
409
+ // Vibration lors du changement de vitesse
410
+ applyVibration(0.2);
411
+
412
+ // Secousse du moteur si changement à haut régime
413
+ if (parseInt(rpmDisplay.textContent) > 3000) {
414
+ dashboard.classList.add('engine-shake');
415
+ setTimeout(() => dashboard.classList.remove('engine-shake'), 500);
416
+ }
417
+ }
418
  });
419
 
420
  gearDownBtn.addEventListener('click', () => {
421
+ if (gear > 1) {
422
+ gear--;
423
+ gearSound.currentTime = 0;
424
+ gearSound.play();
425
+ updateGearDisplay();
426
+ // Vibration lors du changement de vitesse
427
+ applyVibration(0.15);
428
+ }
429
  });
430
 
431
+ // Fonction pour appliquer des effets de vibration
432
+ function applyVibration(intensity) {
433
+ vibrationIntensity = Math.min(1, Math.max(0, intensity));
434
+
435
+ // Mettre à jour l'indicateur visuel
436
+ vibrationIndicator.style.width = `${vibrationIntensity * 100}%`;
437
+
438
+ if (vibrationIntensity > 0.3) {
439
+ vibrationIndicator.classList.add('bg-red-500');
440
+ vibrationIndicator.classList.remove('bg-blue-500');
441
+ } else {
442
+ vibrationIndicator.classList.add('bg-blue-500');
443
+ vibrationIndicator.classList.remove('bg-red-500');
444
+ }
445
+
446
+ // Appliquer les effets visuels
447
+ if (vibrationIntensity > 0.1) {
448
+ panoramicContainer.classList.add('vibration-effect');
449
+ dashboard.classList.add('vibration-effect');
450
+ document.querySelectorAll('.vibration-text').forEach(el => {
451
+ el.classList.add('vibration-effect');
452
+ });
453
+
454
+ // Ajuster la vitesse d'animation en fonction de l'intensité
455
+ const style = document.createElement('style');
456
+ style.id = 'vibration-style';
457
+ style.innerHTML = `
458
+ .vibration-effect {
459
+ animation-duration: ${0.5 / vibrationIntensity}s;
460
+ }
461
+ `;
462
+ const existingStyle = document.getElementById('vibration-style');
463
+ if (existingStyle) existingStyle.remove();
464
+ document.head.appendChild(style);
465
+ } else {
466
+ panoramicContainer.classList.remove('vibration-effect');
467
+ dashboard.classList.remove('vibration-effect');
468
+ document.querySelectorAll('.vibration-text').forEach(el => {
469
+ el.classList.remove('vibration-effect');
470
+ });
471
+ }
472
+
473
+ // Effet sur le volant
474
+ if (vibrationIntensity > 0.5 && !isSteering) {
475
+ steeringWheel.style.transform = `rotate(${Math.sin(Date.now() / 100) * 10 * vibrationIntensity}deg)`;
476
+ }
477
  }
478
 
479
+ // Mise à jour des rétroviseurs avec effets
480
  function updateMirrors() {
481
  if (!currentEnvironment) return;
482
 
 
483
  const mirrorOffset = steeringAngle * 2;
484
+ const speedEffect = Math.min(1, speed / 100);
485
 
486
  // Rétroviseur gauche
487
  leftMirror.style.backgroundImage = mainView.style.backgroundImage;
 
492
  rightMirror.style.backgroundImage = mainView.style.backgroundImage;
493
  rightMirror.style.backgroundPositionX = `${50 + mirrorOffset}%`;
494
 
495
+ // Effet de flou en mouvement
496
+ if (speed > 30) {
497
+ const blurAmount = Math.min(3, speed / 30);
498
+ leftMirror.style.filter = `blur(${blurAmount * 0.5}px)`;
499
+ rightMirror.style.filter = `blur(${blurAmount * 0.5}px)`;
500
+ } else {
501
+ leftMirror.style.filter = 'none';
502
+ rightMirror.style.filter = 'none';
503
+ }
504
  }
505
 
506
+ // Changer d'environnement avec effets météo
507
+ function changeEnvironment(env, imgUrl, weather) {
508
  currentEnvironment = env;
509
+ roadCondition = weather === 'neige' ? 'neige' :
510
+ weather === 'pluie' ? 'mouillé' :
511
+ weather === 'sable' ? 'sable' : 'sec';
512
+
513
  mainView.style.backgroundImage = `url('${imgUrl}')`;
514
 
515
  // Mettre à jour les rétroviseurs
 
519
  speed = 0;
520
  updateSpeedDisplay();
521
 
522
+ // Effets météo
523
+ weatherEffects.innerHTML = '';
524
+ rainSound.pause();
525
+ windSound.pause();
526
+
527
+ if (weather === 'pluie') {
528
+ // Créer un effet de pluie
529
+ for (let i = 0; i < 100; i++) {
530
+ const drop = document.createElement('div');
531
+ drop.className = 'absolute bg-blue-300 rounded-full';
532
+ drop.style.width = `${Math.random() * 2 + 1}px`;
533
+ drop.style.height = `${Math.random() * 10 + 5}px`;
534
+ drop.style.left = `${Math.random() * 100}%`;
535
+ drop.style.top = `${Math.random() * 100}%`;
536
+ drop.style.opacity = Math.random() * 0.6 + 0.2;
537
+ drop.style.animation = `rain ${Math.random() * 0.5 + 0.5}s linear infinite`;
538
+ drop.style.animationDelay = `${Math.random()}s`;
539
+ weatherEffects.appendChild(drop);
540
+ }
541
+
542
+ // Ajouter du son de pluie
543
+ rainSound.currentTime = 0;
544
+ rainSound.volume = 0.3;
545
+ rainSound.play();
546
+
547
+ // Style pour l'animation de pluie
548
+ const rainStyle = document.createElement('style');
549
+ rainStyle.innerHTML = `
550
+ @keyframes rain {
551
+ to {
552
+ transform: translateY(100vh);
553
+ }
554
+ }
555
+ `;
556
+ document.head.appendChild(rainStyle);
557
+
558
+ suspensionStatus = 'mouillé';
559
+ }
560
+ else if (weather === 'neige') {
561
+ // Créer un effet de neige
562
+ for (let i = 0; i < 50; i++) {
563
+ const flake = document.createElement('div');
564
+ flake.className = 'absolute bg-white rounded-full';
565
+ flake.style.width = flake.style.height = `${Math.random() * 5 + 2}px`;
566
+ flake.style.left = `${Math.random() * 100}%`;
567
+ flake.style.top = `${Math.random() * 100}%`;
568
+ flake.style.opacity = Math.random() * 0.8 + 0.2;
569
+ flake.style.animation = `snow ${Math.random() * 10 + 5}s linear infinite`;
570
+ flake.style.animationDelay = `${Math.random()}s`;
571
+ weatherEffects.appendChild(flake);
572
+ }
573
+
574
+ // Ajouter du son de vent
575
+ windSound.currentTime = 0;
576
+ windSound.volume = 0.4;
577
+ windSound.play();
578
+
579
+ // Style pour l'animation de neige
580
+ const snowStyle = document.createElement('style');
581
+ snowStyle.innerHTML = `
582
+ @keyframes snow {
583
+ 0% {
584
+ transform: translateY(-10px) translateX(0);
585
+ }
586
+ 100% {
587
+ transform: translateY(100vh) translateX(${Math.random() * 100 - 50}px);
588
+ }
589
+ }
590
+ `;
591
+ document.head.appendChild(snowStyle);
592
+
593
+ suspensionStatus = 'neige';
594
+ }
595
+ else if (weather === 'sable') {
596
+ // Créer un effet de sable/vents de sable
597
+ for (let i = 0; i < 30; i++) {
598
+ const sand = document.createElement('div');
599
+ sand.className = 'absolute bg-yellow-200 rounded-full';
600
+ sand.style.width = `${Math.random() * 10 + 5}px`;
601
+ sand.style.height = `${Math.random() * 3 + 1}px`;
602
+ sand.style.left = `${Math.random() * 100}%`;
603
+ sand.style.top = `${Math.random() * 100}%`;
604
+ sand.style.opacity = Math.random() * 0.4 + 0.1;
605
+ sand.style.animation = `sand ${Math.random() * 5 + 3}s linear infinite`;
606
+ sand.style.animationDelay = `${Math.random()}s`;
607
+ weatherEffects.appendChild(sand);
608
+ }
609
+
610
+ // Ajouter du son de vent
611
+ windSound.currentTime = 0;
612
+ windSound.volume = 0.5;
613
+ windSound.play();
614
+
615
+ // Style pour l'animation de sable
616
+ const sandStyle = document.createElement('style');
617
+ sandStyle.innerHTML = `
618
+ @keyframes sand {
619
+ 0% {
620
+ transform: translateX(-10px) rotate(0deg);
621
+ }
622
+ 100% {
623
+ transform: translateX(100vw) rotate(${Math.random() * 360}deg);
624
+ }
625
+ }
626
+ `;
627
+ document.head.appendChild(sandStyle);
628
+
629
+ suspensionStatus = 'sable';
630
+ }
631
+ else {
632
+ suspensionStatus = 'normal';
633
+ }
634
+
635
+ suspensionDisplay.textContent = suspensionStatus;
636
+
637
  // Jouer un son d'ambiance différent selon l'environnement
638
  const ambientSound = new Audio();
639
  switch(env) {
 
661
  ambientSound.play();
662
  }
663
 
664
+ // Mise à jour de l'affichage de la vitesse avec effets
665
  function updateSpeedDisplay() {
666
  speedDisplay.textContent = Math.floor(speed);
667
  bigSpeedDisplay.textContent = Math.floor(speed);
 
676
  arc.setAttribute('d', describeArc(50, 50, 35, 0, arcAngle));
677
 
678
  // Mettre à jour le RPM
679
+ const rpm = 800 + (speed * 20 / gear);
680
+ rpmDisplay.textContent = Math.floor(rpm);
681
+
682
+ // Effet de vibration du moteur à haut régime
683
+ if (rpm > 3500) {
684
+ applyVibration(0.3 + (rpm - 3500) / 5000);
685
+ dashboard.classList.add('engine-shake');
686
+ } else {
687
+ dashboard.classList.remove('engine-shake');
688
+ if (vibrationIntensity < 0.2) {
689
+ applyVibration(0);
690
+ }
691
+ }
692
 
693
  // Mettre à jour la distance parcourue
694
+ distance += speed / 36000; // Ajouter la distance en km (vitesse en km/h, 1 heure = 3600 secondes)
695
  distanceDisplay.textContent = distance.toFixed(2);
696
 
697
  // Mettre à jour le niveau de carburant
698
+ fuel = Math.max(0, fuel - (speed / 50000));
699
  fuelLevel.style.width = `${fuel}%`;
700
+ if (fuel < 20) {
701
+ fuelLevel.classList.add('bg-red-500');
702
+ fuelLevel.classList.remove('bg-yellow-500');
703
+
704
+ // Effet de vibration si essence faible
705
+ if (Math.random() > 0.9 && speed > 40) {
706
+ applyVibration(0.4);
707
+ }
708
+ } else {
709
+ fuelLevel.classList.add('bg-yellow-500');
710
+ fuelLevel.classList.remove('bg-red-500');
711
+ }
712
 
713
  // Ajuster le son du moteur
714
  engineSound.volume = 0.3 + (speed / 140) * 0.7;
715
  engineSound.playbackRate = 0.8 + (speed / 140) * 0.8;
716
+
717
+ // Effets de route en fonction de la condition
718
+ if (speed > 20 && Date.now() - lastBumpTime > 3000) {
719
+ const bumpChance = roadCondition === 'mouillé' ? 0.02 :
720
+ roadCondition === 'neige' ? 0.05 :
721
+ roadCondition === 'sable' ? 0.08 : 0.01;
722
+
723
+ if (Math.random() < bumpChance) {
724
+ // Bosse sur la route
725
+ const bumpIntensity = roadCondition === 'neige' ? 0.6 :
726
+ roadCondition === 'sable' ? 0.8 : 0.4;
727
+
728
+ applyVibration(bumpIntensity);
729
+ panoramicContainer.classList.add('road-bump');
730
+ setTimeout(() => panoramicContainer.classList.remove('road-bump'), 500);
731
+
732
+ // Son de bosse
733
+ bumpSound.currentTime = 0;
734
+ bumpSound.volume = 0.3 + (speed / 140) * 0.5;
735
+ bumpSound.play();
736
+
737
+ lastBumpTime = Date.now();
738
+ }
739
+ }
740
  }
741
 
742
  // Fonction pour décrire un arc en SVG
 
755
  };
756
  }
757
 
758
+ // Boucle de simulation améliorée
759
  function simulate() {
760
  if (isAccelerating && fuel > 0) {
761
+ const acceleration = 0.2 * gear;
762
+ const maxSpeed = roadCondition === 'mouillé' ? 120 :
763
+ roadCondition === 'neige' ? 100 :
764
+ roadCondition === 'sable' ? 90 : 140;
765
+
766
+ speed = Math.min(maxSpeed, speed + acceleration);
767
+
768
+ // Vibration lors de l'accélération
769
+ if (gear < 3 && speed < 30) {
770
+ applyVibration(0.1 + (speed / 30) * 0.2);
771
+ }
772
  } else if (isBraking) {
773
+ const brakingPower = roadCondition === 'mouillé' ? 0.3 :
774
+ roadCondition === 'neige' ? 0.2 :
775
+ roadCondition === 'sable' ? 0.25 : 0.5;
776
+
777
+ speed = Math.max(0, speed - brakingPower);
778
+
779
+ // Vibration lors du freinage brusque
780
+ if (speed > 60) {
781
+ applyVibration(0.4);
782
+ }
783
  } else {
784
  // Ralentissement naturel
785
+ const deceleration = roadCondition === 'mouillé' ? 0.03 :
786
+ roadCondition === 'neige' ? 0.04 :
787
+ roadCondition === 'sable' ? 0.05 : 0.02;
788
+
789
+ speed = Math.max(0, speed - deceleration);
790
+ }
791
+
792
+ // Effets de dérive en fonction de la condition de route
793
+ if (speed > 50 && Math.abs(steeringAngle) > 20) {
794
+ const driftEffect = roadCondition === 'mouillé' ? 0.8 :
795
+ roadCondition === 'neige' ? 1.2 :
796
+ roadCondition === 'sable' ? 1.5 : 0.5;
797
+
798
+ applyVibration(driftEffect * (speed / 100) * (Math.abs(steeringAngle) / 90));
799
  }
800
 
801
  updateSpeedDisplay();
 
805
  // Démarrer la simulation
806
  simulate();
807
 
808
+ // Gestion du clavier avec effets
809
  document.addEventListener('keydown', (e) => {
810
  switch(e.key) {
811
  case 'ArrowUp':
812
  isAccelerating = true;
813
+ if (speed < 5) {
814
+ engineSound.currentTime = 0;
815
+ engineSound.play();
816
+ }
817
+ applyVibration(0.1);
818
  break;
819
  case 'ArrowDown':
820
  isBraking = true;
821
+ if (speed > 20) {
822
+ applyVibration(0.3);
823
+ }
824
  break;
825
  case 'ArrowLeft':
826
  steeringAngle = Math.max(-90, steeringAngle - 5);
827
  steeringWheel.style.transform = `rotate(${steeringAngle}deg)`;
828
+ panoramicContainer.style.transform = `rotateY(${steeringAngle / 10}deg)`;
829
  updateMirrors();
830
+ if (speed > 30) {
831
+ applyVibration(0.2);
832
+ }
833
  break;
834
  case 'ArrowRight':
835
  steeringAngle = Math.min(90, steeringAngle + 5);
836
  steeringWheel.style.transform = `rotate(${steeringAngle}deg)`;
837
+ panoramicContainer.style.transform = `rotateY(${steeringAngle / 10}deg)`;
838
  updateMirrors();
839
+ if (speed > 30) {
840
+ applyVibration(0.2);
841
+ }
842
  break;
843
  case ' ':
844
  hornSound.currentTime = 0;
845
  hornSound.play();
846
+ applyVibration(0.4);
847
  break;
848
  case 'l':
849
+ case 'L':
850
  lightsOn = !lightsOn;
851
  lightsBtn.innerHTML = lightsOn ?
852
  '<i class="fas fa-lightbulb mr-2 text-yellow-300"></i> Phares (ON)' :
853
  '<i class="fas fa-lightbulb mr-2"></i> Phares';
854
+ applyVibration(0.05);
855
  break;
856
  case '+':
857
+ if (gear < 10) {
858
+ gear++;
859
+ gearSound.currentTime = 0;
860
+ gearSound.play();
861
+ updateGearDisplay();
862
+ applyVibration(0.2);
863
+ }
864
  break;
865
  case '-':
866
+ if (gear > 1) {
867
+ gear--;
868
+ gearSound.currentTime = 0;
869
+ gearSound.play();
870
+ updateGearDisplay();
871
+ applyVibration(0.15);
872
+ }
873
  break;
874
  }
875
  });
 
884
  break;
885
  }
886
  });
887
+
888
+ // Vibration pour mobile
889
+ if ('vibrate' in navigator) {
890
+ setInterval(() => {
891
+ if (vibrationIntensity > 0.3) {
892
+ navigator.vibrate([50 * vibrationIntensity]);
893
+ }
894
+ }, 500);
895
+ }
896
  </script>
897
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=docto41/simulator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
898
  </html>
prompts.txt CHANGED
@@ -1 +1,2 @@
1
- je veux conduire un camion norml et ree avec vue de partout et paysage
 
 
1
+ je veux conduire un camion norml et ree avec vue de partout et paysage
2
+ je veu conduire avec les vrai sensation le vibrasion comme si on y ete