Mousco commited on
Commit
bbaa0ce
·
verified ·
1 Parent(s): 755610b

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +792 -19
index.html CHANGED
@@ -1,19 +1,792 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Aviator Aléatoire - Jeu Web</title>
7
+ <!-- Importation de FontAwesome pour les icônes -->
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <!-- Police Google Fonts -->
10
+ <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Roboto:wght@300;400;700&display=swap" rel="stylesheet">
11
+
12
+ <style>
13
+ :root {
14
+ --bg-dark: #0f1923;
15
+ --bg-panel: #1b2733;
16
+ --primary: #e50914; /* Rouge crash */
17
+ --accent: #4ade80; /* Vert gain */
18
+ --text-main: #ffffff;
19
+ --text-muted: #8b9bb4;
20
+ --grid-line: rgba(255, 255, 255, 0.05);
21
+ --border-radius: 12px;
22
+ --glow: 0 0 15px rgba(74, 222, 128, 0.3);
23
+ }
24
+
25
+ * {
26
+ box-sizing: border-box;
27
+ margin: 0;
28
+ padding: 0;
29
+ user-select: none; /* Empêche la sélection de texte pendant le jeu */
30
+ }
31
+
32
+ body {
33
+ font-family: 'Roboto', sans-serif;
34
+ background-color: var(--bg-dark);
35
+ color: var(--text-main);
36
+ height: 100vh;
37
+ display: flex;
38
+ flex-direction: column;
39
+ overflow: hidden;
40
+ }
41
+
42
+ /* --- Header --- */
43
+ header {
44
+ height: 60px;
45
+ background-color: var(--bg-panel);
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: space-between;
49
+ padding: 0 20px;
50
+ border-bottom: 1px solid rgba(255,255,255,0.1);
51
+ z-index: 10;
52
+ }
53
+
54
+ .logo {
55
+ font-family: 'Orbitron', sans-serif;
56
+ font-size: 1.5rem;
57
+ font-weight: 900;
58
+ color: var(--text-main);
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 10px;
62
+ }
63
+
64
+ .logo i {
65
+ color: var(--primary);
66
+ }
67
+
68
+ .built-with {
69
+ font-size: 0.85rem;
70
+ color: var(--text-muted);
71
+ text-decoration: none;
72
+ transition: color 0.3s;
73
+ }
74
+
75
+ .built-with:hover {
76
+ color: var(--accent);
77
+ }
78
+
79
+ /* --- Main Layout --- */
80
+ main {
81
+ flex: 1;
82
+ display: grid;
83
+ grid-template-columns: 1fr 350px;
84
+ gap: 20px;
85
+ padding: 20px;
86
+ height: calc(100vh - 60px);
87
+ }
88
+
89
+ /* --- Game Area (Canvas) --- */
90
+ #game-container {
91
+ background-color: var(--bg-panel);
92
+ border-radius: var(--border-radius);
93
+ position: relative;
94
+ overflow: hidden;
95
+ display: flex;
96
+ flex-direction: column;
97
+ box-shadow: 0 4px 20px rgba(0,0,0,0.3);
98
+ }
99
+
100
+ #history-bar {
101
+ height: 40px;
102
+ display: flex;
103
+ align-items: center;
104
+ gap: 8px;
105
+ padding: 0 15px;
106
+ background: rgba(0,0,0,0.2);
107
+ overflow-x: auto;
108
+ }
109
+
110
+ /* Scrollbar customisée */
111
+ #history-bar::-webkit-scrollbar { height: 4px; }
112
+ #history-bar::-webkit-scrollbar-thumb { background: #333; border-radius: 2px; }
113
+
114
+ .history-badge {
115
+ padding: 2px 8px;
116
+ border-radius: 4px;
117
+ font-size: 0.8rem;
118
+ font-weight: bold;
119
+ min-width: 50px;
120
+ text-align: center;
121
+ }
122
+ .badge-low { background: rgba(229, 9, 20, 0.2); color: var(--primary); }
123
+ .badge-high { background: rgba(74, 222, 128, 0.2); color: var(--accent); }
124
+
125
+ #canvas-wrapper {
126
+ flex: 1;
127
+ position: relative;
128
+ width: 100%;
129
+ height: 100%;
130
+ }
131
+
132
+ canvas {
133
+ display: block;
134
+ width: 100%;
135
+ height: 100%;
136
+ }
137
+
138
+ #multiplier-overlay {
139
+ position: absolute;
140
+ top: 50%;
141
+ left: 50%;
142
+ transform: translate(-50%, -50%);
143
+ font-family: 'Orbitron', sans-serif;
144
+ font-size: 5rem;
145
+ font-weight: 700;
146
+ color: rgba(255,255,255,0.1);
147
+ pointer-events: none;
148
+ transition: color 0.2s;
149
+ }
150
+
151
+ /* --- Sidebar Controls --- */
152
+ #sidebar {
153
+ background-color: var(--bg-panel);
154
+ border-radius: var(--border-radius);
155
+ padding: 25px;
156
+ display: flex;
157
+ flex-direction: column;
158
+ gap: 20px;
159
+ box-shadow: 0 4px 20px rgba(0,0,0,0.3);
160
+ }
161
+
162
+ .balance-card {
163
+ background: rgba(255,255,255,0.05);
164
+ padding: 15px;
165
+ border-radius: 8px;
166
+ text-align: center;
167
+ }
168
+
169
+ .balance-label {
170
+ font-size: 0.9rem;
171
+ color: var(--text-muted);
172
+ margin-bottom: 5px;
173
+ }
174
+
175
+ .balance-amount {
176
+ font-size: 1.8rem;
177
+ font-weight: bold;
178
+ color: var(--text-main);
179
+ }
180
+
181
+ .control-group {
182
+ display: flex;
183
+ flex-direction: column;
184
+ gap: 10px;
185
+ }
186
+
187
+ label {
188
+ font-size: 0.9rem;
189
+ color: var(--text-muted);
190
+ }
191
+
192
+ .input-wrapper {
193
+ position: relative;
194
+ display: flex;
195
+ align-items: center;
196
+ }
197
+
198
+ .currency-symbol {
199
+ position: absolute;
200
+ left: 15px;
201
+ color: var(--text-muted);
202
+ }
203
+
204
+ input[type="number"] {
205
+ width: 100%;
206
+ background: rgba(0,0,0,0.3);
207
+ border: 1px solid rgba(255,255,255,0.1);
208
+ padding: 12px 12px 12px 35px;
209
+ border-radius: 8px;
210
+ color: white;
211
+ font-size: 1.1rem;
212
+ font-family: 'Roboto', sans-serif;
213
+ outline: none;
214
+ transition: border-color 0.3s;
215
+ }
216
+
217
+ input[type="number"]:focus {
218
+ border-color: var(--accent);
219
+ }
220
+
221
+ .quick-amounts {
222
+ display: flex;
223
+ gap: 10px;
224
+ }
225
+
226
+ .btn-quick {
227
+ background: rgba(255,255,255,0.1);
228
+ border: none;
229
+ color: var(--text-muted);
230
+ padding: 5px 10px;
231
+ border-radius: 4px;
232
+ cursor: pointer;
233
+ font-size: 0.8rem;
234
+ transition: all 0.2s;
235
+ }
236
+
237
+ .btn-quick:hover {
238
+ background: rgba(255,255,255,0.2);
239
+ color: white;
240
+ }
241
+
242
+ #action-btn {
243
+ width: 100%;
244
+ padding: 18px;
245
+ border: none;
246
+ border-radius: 8px;
247
+ font-size: 1.2rem;
248
+ font-weight: bold;
249
+ text-transform: uppercase;
250
+ cursor: pointer;
251
+ transition: transform 0.1s, box-shadow 0.3s;
252
+ font-family: 'Orbitron', sans-serif;
253
+ }
254
+
255
+ .btn-bet {
256
+ background: linear-gradient(135deg, #e50914 0%, #b20710 100%);
257
+ color: white;
258
+ box-shadow: 0 4px 15px rgba(229, 9, 20, 0.4);
259
+ }
260
+
261
+ .btn-cashout {
262
+ background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%);
263
+ color: #064e3b;
264
+ box-shadow: 0 4px 15px rgba(74, 222, 128, 0.4);
265
+ }
266
+
267
+ .btn-disabled {
268
+ background: #333;
269
+ color: #777;
270
+ cursor: not-allowed;
271
+ box-shadow: none;
272
+ }
273
+
274
+ #action-btn:active:not(.btn-disabled) {
275
+ transform: scale(0.98);
276
+ }
277
+
278
+ .status-msg {
279
+ text-align: center;
280
+ font-size: 0.9rem;
281
+ min-height: 1.2em;
282
+ }
283
+
284
+ /* --- Footer/Stats --- */
285
+ .stats-row {
286
+ margin-top: auto;
287
+ display: flex;
288
+ justify-content: space-between;
289
+ padding-top: 20px;
290
+ border-top: 1px solid rgba(255,255,255,0.1);
291
+ font-size: 0.9rem;
292
+ color: var(--text-muted);
293
+ }
294
+
295
+ /* --- Toast Notifications --- */
296
+ #toast-container {
297
+ position: fixed;
298
+ bottom: 20px;
299
+ right: 20px;
300
+ display: flex;
301
+ flex-direction: column;
302
+ gap: 10px;
303
+ z-index: 100;
304
+ }
305
+
306
+ .toast {
307
+ background: var(--bg-panel);
308
+ border-left: 4px solid var(--accent);
309
+ padding: 15px 20px;
310
+ border-radius: 4px;
311
+ box-shadow: 0 5px 15px rgba(0,0,0,0.5);
312
+ display: flex;
313
+ align-items: center;
314
+ gap: 10px;
315
+ animation: slideIn 0.3s ease-out forwards;
316
+ min-width: 250px;
317
+ }
318
+
319
+ .toast.error { border-left-color: var(--primary); }
320
+ .toast i { font-size: 1.2rem; }
321
+
322
+ @keyframes slideIn {
323
+ from { transform: translateX(100%); opacity: 0; }
324
+ to { transform: translateX(0); opacity: 1; }
325
+ }
326
+
327
+ @keyframes fadeOut {
328
+ to { opacity: 0; transform: translateX(20px); }
329
+ }
330
+
331
+ /* --- Responsive Design --- */
332
+ @media (max-width: 900px) {
333
+ main {
334
+ grid-template-columns: 1fr;
335
+ grid-template-rows: 1fr auto;
336
+ height: auto;
337
+ overflow-y: auto;
338
+ }
339
+
340
+ #game-container {
341
+ height: 50vh;
342
+ }
343
+
344
+ #sidebar {
345
+ height: auto;
346
+ }
347
+ }
348
+ </style>
349
+ </head>
350
+ <body>
351
+
352
+ <header>
353
+ <div class="logo">
354
+ <i class="fa-solid fa-plane-up"></i>
355
+ <span>AVIATOR</span>
356
+ </div>
357
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with">
358
+ Built with anycoder <i class="fa-solid fa-external-link-alt"></i>
359
+ </a>
360
+ </header>
361
+
362
+ <main>
363
+ <!-- Zone de Jeu -->
364
+ <section id="game-container">
365
+ <div id="history-bar">
366
+ <!-- Historique rempli par JS -->
367
+ </div>
368
+ <div id="canvas-wrapper">
369
+ <canvas id="gameCanvas"></canvas>
370
+ <div id="multiplier-overlay">1.00x</div>
371
+ </div>
372
+ </section>
373
+
374
+ <!-- Contrôles -->
375
+ <section id="sidebar">
376
+ <div class="balance-card">
377
+ <div class="balance-label">Solde Disponible</div>
378
+ <div class="balance-amount">$<span id="balance">1000.00</span></div>
379
+ </div>
380
+
381
+ <div class="control-group">
382
+ <label for="bet-input">Montant du pari</label>
383
+ <div class="input-wrapper">
384
+ <span class="currency-symbol">$</span>
385
+ <input type="number" id="bet-input" value="10.00" min="1.00" step="1.00">
386
+ </div>
387
+ <div class="quick-amounts">
388
+ <button class="btn-quick" onclick="setBet(10)">10</button>
389
+ <button class="btn-quick" onclick="setBet(50)">50</button>
390
+ <button class="btn-quick" onclick="setBet(100)">100</button>
391
+ <button class="btn-quick" onclick="setBet(maxBet())">Max</button>
392
+ </div>
393
+ </div>
394
+
395
+ <div id="status-display" class="status-msg">Prêt pour le décollage</div>
396
+
397
+ <button id="action-btn" class="btn-bet">MISER</button>
398
+
399
+ <div class="stats-row">
400
+ <span>Dernier gain: <span id="last-win" style="color:white">$0.00</span></span>
401
+ <span>Meilleur: <span id="best-crash" style="color:white">-</span></span>
402
+ </div>
403
+ </section>
404
+ </main>
405
+
406
+ <div id="toast-container"></div>
407
+
408
+ <script>
409
+ // --- Configuration du Jeu ---
410
+ const config = {
411
+ maxSpeed: 0.05, // Vitesse d'augmentation du multiplicateur par frame
412
+ crashProbability: 0.05 // Facteur pour l'algorithme de crash
413
+ };
414
+
415
+ // --- État du Jeu ---
416
+ const state = {
417
+ balance: 1000.00,
418
+ currentBet: 0,
419
+ isBetPlaced: false,
420
+ gameStatus: 'IDLE', // IDLE, FLYING, CRASHED
421
+ multiplier: 1.00,
422
+ crashPoint: 0,
423
+ history: [],
424
+ startTime: 0,
425
+ animationId: null
426
+ };
427
+
428
+ // --- Éléments DOM ---
429
+ const canvas = document.getElementById('gameCanvas');
430
+ const ctx = canvas.getContext('2d');
431
+ const multiplierEl = document.getElementById('multiplier-overlay');
432
+ const balanceEl = document.getElementById('balance');
433
+ const betInput = document.getElementById('bet-input');
434
+ const actionBtn = document.getElementById('action-btn');
435
+ const statusEl = document.getElementById('status-display');
436
+ const historyContainer = document.getElementById('history-bar');
437
+ const lastWinEl = document.getElementById('last-win');
438
+ const bestCrashEl = document.getElementById('best-crash');
439
+
440
+ // --- Redimensionnement du Canvas ---
441
+ let width, height;
442
+ function resizeCanvas() {
443
+ const wrapper = document.getElementById('canvas-wrapper');
444
+ width = wrapper.clientWidth;
445
+ height = wrapper.clientHeight;
446
+ canvas.width = width;
447
+ canvas.height = height;
448
+ }
449
+ window.addEventListener('resize', resizeCanvas);
450
+ resizeCanvas();
451
+
452
+ // --- Utilitaires ---
453
+ function formatMoney(amount) {
454
+ return amount.toFixed(2);
455
+ }
456
+
457
+ function showToast(message, type = 'success') {
458
+ const container = document.getElementById('toast-container');
459
+ const toast = document.createElement('div');
460
+ toast.className = `toast ${type}`;
461
+
462
+ const icon = type === 'success' ? 'fa-check-circle' : 'fa-exclamation-circle';
463
+ toast.innerHTML = `<i class="fa-solid ${icon}"></i> <span>${message}</span>`;
464
+
465
+ container.appendChild(toast);
466
+
467
+ // Auto remove
468
+ setTimeout(() => {
469
+ toast.style.animation = 'fadeOut 0.3s ease-out forwards';
470
+ toast.addEventListener('animationend', () => toast.remove());
471
+ }, 3000);
472
+ }
473
+
474
+ function setBet(amount) {
475
+ if (state.gameStatus !== 'IDLE') return;
476
+ betInput.value = amount;
477
+ }
478
+
479
+ function maxBet() {
480
+ return state.balance;
481
+ }
482
+
483
+ // --- Logique RNG (Génération Aléatoire) ---
484
+ // Utilise une distribution inverse pour favoriser les petits nombres mais permettre des crashs élevés
485
+ function generateCrashPoint() {
486
+ // Formule standard: E = 100 / (1 - random)
487
+ // Nous ajustons pour que le minimum soit souvent 1.00x
488
+ const r = Math.random();
489
+ // House edge simulée (3%)
490
+ const crashPoint = (0.97 / (1 - r));
491
+
492
+ // Arrondir à 2 décimales, minimum 1.00
493
+ let finalCrash = Math.floor(crashPoint * 100) / 100;
494
+ if (finalCrash < 1.00) finalCrash = 1.00;
495
+
496
+ return finalCrash;
497
+ }
498
+
499
+ // --- Boucle de Jeu et Rendu ---
500
+ function startGame() {
501
+ // Validation
502
+ const betAmount = parseFloat(betInput.value);
503
+ if (isNaN(betAmount) || betAmount <= 0) {
504
+ showToast("Veuillez entrer un montant valide.", "error");
505
+ return;
506
+ }
507
+ if (betAmount > state.balance) {
508
+ showToast("Fonds insuffisants.", "error");
509
+ return;
510
+ }
511
+
512
+ // Mise à jour état
513
+ state.balance -= betAmount;
514
+ state.currentBet = betAmount;
515
+ state.isBetPlaced = true;
516
+ state.gameStatus = 'FLYING';
517
+ state.crashPoint = generateCrashPoint();
518
+ state.startTime = Date.now();
519
+ state.multiplier = 1.00;
520
+
521
+ updateUI();
522
+
523
+ // Démarrage animation
524
+ if (state.animationId) cancelAnimationFrame(state.animationId);
525
+ gameLoop();
526
+ }
527
+
528
+ function cashOut() {
529
+ if (!state.isBetPlaced || state.gameStatus !== 'FLYING') return;
530
+
531
+ const winAmount = state.currentBet * state.multiplier;
532
+ state.balance += winAmount;
533
+ state.isBetPlaced = false; // Plus de pari en cours
534
+
535
+ lastWinEl.textContent = `$${formatMoney(winAmount)}`;
536
+ showToast(`Gagné! $${formatMoney(winAmount)} à ${state.multiplier.toFixed(2)}x`, "success");
537
+
538
+ updateUI();
539
+
540
+ // Désactiver le bouton cashout visuellement
541
+ actionBtn.className = 'btn-disabled';
542
+ actionBtn.textContent = 'EN ATTENTE...';
543
+ }
544
+
545
+ function endGame() {
546
+ state.gameStatus = 'CRASHED';
547
+ state.isBetPlaced = false;
548
+ state.multiplier = state.crashPoint;
549
+
550
+ // Mise à jour historique
551
+ addToHistory(state.crashPoint);
552
+
553
+ // Message si le joueur avait misé et n'a pas cashout
554
+ const betAmount = parseFloat(betInput.value);
555
+ if (state.currentBet > 0 && state.currentBet === betAmount) {
556
+ // Logique simple : si on crash et qu'on a encore un bet actif en mémoire (simplifié ici)
557
+ // Dans ce code simple, si on n'a pas cashout, on a perdu.
558
+ showToast(`L'avion a parti à ${state.crashPoint}x`, "error");
559
+ }
560
+
561
+ updateUI();
562
+
563
+ // Redémarrage automatique après 5 secondes
564
+ statusEl.textContent = "Prochain décollage dans 5s...";
565
+ setTimeout(() => {
566
+ resetGame();
567
+ }, 5000);
568
+ }
569
+
570
+ function resetGame() {
571
+ state.gameStatus = 'IDLE';
572
+ state.multiplier = 1.00;
573
+ state.crashPoint = 0;
574
+ updateUI();
575
+ }
576
+
577
+ function addToHistory(crash) {
578
+ state.history.unshift(crash);
579
+ if (state.history.length > 20) state.history.pop();
580
+
581
+ const badge = document.createElement('div');
582
+ badge.className = `history-badge ${crash >= 2.0 ? 'badge-high' : 'badge-low'}`;
583
+ badge.textContent = `${crash.toFixed(2)}x`;
584
+
585
+ historyContainer.prepend(badge);
586
+ if (historyContainer.children.length > 20) {
587
+ historyContainer.lastChild.remove();
588
+ }
589
+
590
+ // Meilleur crash
591
+ const currentBest = parseFloat(bestCrashEl.textContent) || 0;
592
+ if (crash > currentBest) {
593
+ bestCrashEl.textContent = `${crash.toFixed(2)}x`;
594
+ }
595
+ }
596
+
597
+ function updateUI() {
598
+ balanceEl.textContent = formatMoney(state.balance);
599
+ multiplierEl.textContent = state.multiplier.toFixed(2) + 'x';
600
+
601
+ if (state.gameStatus === 'IDLE') {
602
+ actionBtn.className = 'btn-bet';
603
+ actionBtn.textContent = 'MISER';
604
+ actionBtn.disabled = false;
605
+ actionBtn.style.cursor = 'pointer';
606
+ statusEl.textContent = "Veuillez placer votre pari";
607
+ multiplierEl.style.color = "rgba(255,255,255,0.1)";
608
+ } else if (state.gameStatus === 'FLYING') {
609
+ if (state.isBetPlaced) {
610
+ actionBtn.className = 'btn-cashout';
611
+ actionBtn.textContent = `RETIRER ($${formatMoney(state.currentBet * state.multiplier)})`;
612
+ actionBtn.onclick = cashOut;
613
+ multiplierEl.style.color = "var(--accent)";
614
+ statusEl.textContent = "En vol...";
615
+ } else {
616
+ // En vol mais sans pari (tour suivant)
617
+ actionBtn.className = 'btn-disabled';
618
+ actionBtn.textContent = 'EN VOL';
619
+ multiplierEl.style.color = "var(--text-main)";
620
+ statusEl.textContent = "Trop tard pour miser!";
621
+ }
622
+ } else if (state.gameStatus === 'CRASHED') {
623
+ actionBtn.className = 'btn-disabled';
624
+ actionBtn.textContent = 'CRASHED';
625
+ multiplierEl.style.color = "var(--primary)";
626
+ statusEl.textContent = `Envoyé à ${state.crashPoint.toFixed(2)}x`;
627
+ }
628
+ }
629
+
630
+ // --- Rendu Graphique (Canvas) ---
631
+ function drawGrid() {
632
+ ctx.clearRect(0, 0, width, height);
633
+
634
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.05)';
635
+ ctx.lineWidth = 1;
636
+
637
+ // Lignes verticales
638
+ for (let x = 0; x < width; x += 50) {
639
+ ctx.beginPath();
640
+ ctx.moveTo(x, 0);
641
+ ctx.lineTo(x, height);
642
+ ctx.stroke();
643
+ }
644
+
645
+ // Lignes horizontales
646
+ for (let y = 0; y < height; y += 50) {
647
+ ctx.beginPath();
648
+ ctx.moveTo(0, y);
649
+ ctx.lineTo(width, y);
650
+ ctx.stroke();
651
+ }
652
+ }
653
+
654
+ function gameLoop() {
655
+ if (state.gameStatus !== 'FLYING') return;
656
+
657
+ // Calcul du multiplicateur basé sur le temps
658
+ // Croissance exponentielle simple
659
+ const now = Date.now();
660
+ const elapsed = (now - state.startTime) / 1000;
661
+
662
+ // Formule de croissance: 1 + (elapsed^2) * speed pour une accélération progressive
663
+ state.multiplier = 1 + (elapsed * elapsed * 0.1) + (elapsed * 0.1);
664
+
665
+ // Vérification Crash
666
+ if (state.multiplier >= state.crashPoint) {
667
+ state.multiplier = state.crashPoint; // Clamp pour affichage exact
668
+ drawGrid();
669
+ drawCurve(state.crashPoint, true);
670
+ endGame();
671
+ return;
672
+ }
673
+
674
+ // Mise à jour UI Bouton (montant potentiel)
675
+ if (state.isBetPlaced) {
676
+ actionBtn.textContent = `RETIRER ($${formatMoney(state.currentBet * state.multiplier)})`;
677
+ }
678
+ multiplierEl.textContent = state.multiplier.toFixed(2) + 'x';
679
+
680
+ // Dessin
681
+ drawGrid();
682
+ drawCurve(state.multiplier, false);
683
+
684
+ state.animationId = requestAnimationFrame(gameLoop);
685
+ }
686
+
687
+ function drawCurve(currentMult, isCrashed) {
688
+ ctx.beginPath();
689
+
690
+ // Définition de l'échelle
691
+ // X représente le temps, Y le multiplicateur
692
+ // On veut que la courbe reste visible à l'écran
693
+
694
+ // Echelle Y dynamique : plus le multiplicateur est haut, plus on dézoome
695
+ const scaleY = height / Math.max(2, currentMult * 1.5);
696
+ const scaleX = width / 10; // 10 secondes de largeur virtuelle par défaut
697
+
698
+ // Dessiner la courbe rouge (trajectoire passée)
699
+ ctx.moveTo(0, height - (1 * scaleY)); // Départ à 1x en bas à gauche
700
+
701
+ // Simulation de la courbe quadratique
702
+ // On dessine une courbe de Bézier simple pour l'effet visuel
703
+ const endX = (Math.sqrt(currentMult - 1) * 200) + 50; // Mapping arbitraire pour l'effet visuel
704
+ const endY = height - (currentMult * scaleY);
705
+
706
+ ctx.quadraticCurveTo(endX / 2, height, endX, endY);
707
+
708
+ ctx.lineWidth = 5;
709
+ ctx.strokeStyle = isCrashed ? '#e50914' : '#e50914';
710
+ ctx.stroke();
711
+
712
+ // Ombre/Glow
713
+ ctx.shadowBlur = 10;
714
+ ctx.shadowColor = '#e50914';
715
+ ctx.stroke();
716
+ ctx.shadowBlur = 0;
717
+
718
+ // Dessiner l'avion (ou le point de crash)
719
+ if (!isCrashed) {
720
+ ctx.save();
721
+ ctx.translate(endX, endY);
722
+ // Rotation basée sur la pente
723
+ ctx.rotate(-Math.PI / 4);
724
+
725
+ // Dessin de l'icône avion simplifiée
726
+ ctx.fillStyle = '#ffffff';
727
+ ctx.beginPath();
728
+ ctx.moveTo(10, 0);
729
+ ctx.lineTo(-10, 7);
730
+ ctx.lineTo(-10, -7);
731
+ ctx.fill();
732
+
733
+ // Flamme
734
+ ctx.fillStyle = '#f59e0b';
735
+ ctx.beginPath();
736
+ ctx.moveTo(-10, 0);
737
+ ctx.lineTo(-18, 0);
738
+ ctx.stroke();
739
+
740
+ ctx.restore();
741
+ } else {
742
+ // Dessiner le point de crash
743
+ ctx.fillStyle = '#e50914';
744
+ ctx.beginPath();
745
+ ctx.arc(endX, endY, 6, 0, Math.PI * 2);
746
+ ctx.fill();
747
+
748
+ // Croix
749
+ ctx.strokeStyle = '#fff';
750
+ ctx.lineWidth = 2;
751
+ ctx.beginPath();
752
+ ctx.moveTo(endX - 10, endY - 10);
753
+ ctx.lineTo(endX + 10, endY + 10);
754
+ ctx.moveTo(endX + 10, endY - 10);
755
+ ctx.lineTo(endX - 10, endY + 10);
756
+ ctx.stroke();
757
+ }
758
+ }
759
+
760
+ // --- Event Listeners ---
761
+ actionBtn.addEventListener('click', () => {
762
+ if (state.gameStatus === 'IDLE') {
763
+ startGame();
764
+ } else if (state.gameStatus === 'FLYING' && state.isBetPlaced) {
765
+ cashOut();
766
+ }
767
+ });
768
+
769
+ // Initialisation
770
+ resizeCanvas();
771
+ drawGrid();
772
+
773
+ // Animation d'attente (grille qui scrolle légèrement)
774
+ let bgOffset = 0;
775
+ function idleAnimation() {
776
+ if (state.gameStatus === 'IDLE') {
777
+ bgOffset = (bgOffset + 0.5) % 50;
778
+ drawGrid();
779
+
780
+ // Effet visuel "Ready"
781
+ ctx.fillStyle = "rgba(255, 255, 255, 0.1)";
782
+ ctx.font = "20px Orbitron";
783
+ ctx.textAlign = "center";
784
+ ctx.fillText("EN ATTENTE DE DÉCOLLAGE", width/2, height/2);
785
+ }
786
+ requestAnimationFrame(idleAnimation);
787
+ }
788
+ idleAnimation();
789
+
790
+ </script>
791
+ </body>
792
+ </html>