PAUTREL Johan commited on
Commit
da91a31
·
verified ·
1 Parent(s): 1c15101

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +589 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Ajnet 31
3
- emoji: 📉
4
- colorFrom: indigo
5
- colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: ajnet-31
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,589 @@
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>AJNET 31 - Jeu de Nettoyage Expert</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
+ @keyframes fadeIn {
11
+ from { opacity: 0; }
12
+ to { opacity: 1; }
13
+ }
14
+
15
+ @keyframes pulse {
16
+ 0% { transform: scale(1); }
17
+ 50% { transform: scale(1.05); }
18
+ 100% { transform: scale(1); }
19
+ }
20
+
21
+ @keyframes shake {
22
+ 0%, 100% { transform: translateX(0); }
23
+ 10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
24
+ 20%, 40%, 60%, 80% { transform: translateX(5px); }
25
+ }
26
+
27
+ @keyframes float {
28
+ 0%, 100% { transform: translateY(0); }
29
+ 50% { transform: translateY(-10px); }
30
+ }
31
+
32
+ @keyframes moveRandom {
33
+ 0% { transform: translate(0, 0); }
34
+ 25% { transform: translate(100px, 80px); }
35
+ 50% { transform: translate(50px, -50px); }
36
+ 75% { transform: translate(-80px, 30px); }
37
+ 100% { transform: translate(0, 0); }
38
+ }
39
+
40
+ .stain {
41
+ animation: fadeIn 0.3s ease-in;
42
+ transition: transform 0.2s;
43
+ cursor: pointer;
44
+ }
45
+
46
+ .stain:hover {
47
+ transform: scale(0.95);
48
+ }
49
+
50
+ .moving-stain {
51
+ animation: moveRandom 3s linear infinite;
52
+ }
53
+
54
+ .game-container {
55
+ background-image: linear-gradient(to bottom, #f0f9ff, #e0f2fe);
56
+ }
57
+
58
+ .progress-bar {
59
+ transition: width 0.3s ease-out;
60
+ }
61
+
62
+ .modal {
63
+ animation: fadeIn 0.3s ease-out;
64
+ }
65
+
66
+ .btn-pulse {
67
+ animation: pulse 1.5s infinite;
68
+ }
69
+
70
+ .shake {
71
+ animation: shake 0.5s;
72
+ }
73
+
74
+ .combo-effect {
75
+ position: absolute;
76
+ font-size: 1.5rem;
77
+ font-weight: bold;
78
+ color: #3b82f6;
79
+ opacity: 0;
80
+ animation: fadeIn 0.5s forwards, float 1s forwards;
81
+ }
82
+
83
+ .penalty-effect {
84
+ position: absolute;
85
+ font-size: 1.5rem;
86
+ font-weight: bold;
87
+ color: #ef4444;
88
+ opacity: 0;
89
+ animation: fadeIn 0.5s forwards, shake 0.5s forwards;
90
+ }
91
+
92
+ .rules-modal {
93
+ max-height: 80vh;
94
+ overflow-y: auto;
95
+ }
96
+ </style>
97
+ </head>
98
+ <body class="bg-gray-100 font-sans">
99
+ <div class="min-h-screen flex flex-col">
100
+ <!-- Header -->
101
+ <header class="bg-blue-600 text-white py-4 shadow-lg">
102
+ <div class="container mx-auto px-4 flex justify-between items-center">
103
+ <div class="flex items-center space-x-2">
104
+ <i class="fas fa-broom text-2xl"></i>
105
+ <h1 class="text-2xl font-bold">AJNET 31</h1>
106
+ </div>
107
+ <div class="flex items-center space-x-4">
108
+ <button id="rules-btn" class="bg-blue-800 px-3 py-1 rounded-full font-bold text-sm hover:bg-blue-700 transition">
109
+ <i class="fas fa-info-circle mr-1"></i>Règles
110
+ </button>
111
+ <div id="combo-counter" class="hidden bg-blue-800 px-3 py-1 rounded-full font-bold text-sm">
112
+ Combo x<span id="combo">0</span>
113
+ </div>
114
+ <div id="score-display" class="bg-blue-800 px-4 py-2 rounded-full font-bold">
115
+ Score: <span id="score">0</span>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ </header>
120
+
121
+ <!-- Main Game Area -->
122
+ <main class="flex-grow game-container relative overflow-hidden">
123
+ <div class="absolute top-4 left-4 bg-blue-100 bg-opacity-80 p-2 rounded-lg shadow">
124
+ <div class="flex items-center space-x-2">
125
+ <i class="fas fa-clock text-blue-600"></i>
126
+ <span id="time">60</span>s
127
+ </div>
128
+ <div class="mt-2 w-full bg-gray-200 rounded-full h-2.5">
129
+ <div id="time-bar" class="progress-bar bg-blue-600 h-2.5 rounded-full" style="width: 100%"></div>
130
+ </div>
131
+ </div>
132
+
133
+ <div class="absolute top-4 right-4 bg-blue-100 bg-opacity-80 p-2 rounded-lg shadow">
134
+ <div class="flex items-center space-x-2">
135
+ <i class="fas fa-tachometer-alt text-blue-600"></i>
136
+ Niveau: <span id="level">1</span>
137
+ </div>
138
+ </div>
139
+
140
+ <div id="game-area" class="w-full h-full relative"></div>
141
+
142
+ <!-- Start Screen -->
143
+ <div id="start-screen" class="absolute inset-0 bg-blue-600 bg-opacity-90 flex flex-col items-center justify-center text-white">
144
+ <div class="text-center max-w-md px-6">
145
+ <i class="fas fa-broom text-6xl mb-6"></i>
146
+ <h2 class="text-4xl font-bold mb-4">AJNET 31</h2>
147
+ <p class="text-xl mb-6">Mode Expert: Taches mobiles, combo et pénalités!</p>
148
+ <div class="bg-blue-800 p-4 rounded-lg mb-6 text-left">
149
+ <p class="mb-2"><i class="fas fa-running mr-2"></i> Taches mobiles apparaissent</p>
150
+ <p class="mb-2"><i class="fas fa-bolt mr-2"></i> Combo pour bonus de points</p>
151
+ <p class="mb-2"><i class="fas fa-skull mr-2"></i> Taches spéciales pénalisantes</p>
152
+ </div>
153
+ <button id="start-btn" class="btn-pulse bg-white text-blue-600 font-bold py-3 px-8 rounded-full text-lg hover:bg-blue-100 transition">
154
+ DÉFI EXPERT
155
+ </button>
156
+ </div>
157
+ </div>
158
+
159
+ <!-- Game Over Screen -->
160
+ <div id="game-over" class="modal absolute inset-0 bg-blue-600 bg-opacity-90 hidden flex-col items-center justify-center text-white">
161
+ <div class="text-center max-w-md px-6">
162
+ <i class="fas fa-award text-6xl mb-6"></i>
163
+ <h2 class="text-4xl font-bold mb-4">Performance</h2>
164
+ <div class="bg-blue-800 p-6 rounded-xl mb-6">
165
+ <p class="text-5xl font-bold mb-2" id="final-score">0</p>
166
+ <p class="text-lg">points</p>
167
+ <p class="mt-4"><i class="fas fa-trophy mr-2"></i>Niveau atteint: <span id="final-level">1</span></p>
168
+ <p><i class="fas fa-bolt mr-2"></i>Combo max: x<span id="final-combo">0</span></p>
169
+ </div>
170
+ <div class="flex space-x-4">
171
+ <button id="restart-btn" class="bg-white text-blue-600 font-bold py-3 px-6 rounded-full hover:bg-blue-100 transition">
172
+ <i class="fas fa-redo mr-2"></i>Rejouer
173
+ </button>
174
+ <button id="share-btn" class="bg-blue-800 text-white font-bold py-3 px-6 rounded-full hover:bg-blue-700 transition">
175
+ <i class="fas fa-share-alt mr-2"></i>Partager
176
+ </button>
177
+ </div>
178
+ </div>
179
+ </div>
180
+
181
+ <!-- Rules Modal -->
182
+ <div id="rules-modal" class="modal absolute inset-0 bg-blue-600 bg-opacity-90 hidden flex-col items-center justify-center text-white">
183
+ <div class="rules-modal bg-blue-800 p-6 rounded-xl max-w-md mx-4">
184
+ <div class="flex justify-between items-center mb-4">
185
+ <h2 class="text-2xl font-bold"><i class="fas fa-book mr-2"></i>Règles du Jeu</h2>
186
+ <button id="close-rules-btn" class="text-white hover:text-blue-200 text-2xl">
187
+ <i class="fas fa-times"></i>
188
+ </button>
189
+ </div>
190
+ <div class="space-y-4">
191
+ <div class="bg-blue-700 p-4 rounded-lg">
192
+ <h3 class="font-bold text-lg mb-2"><i class="fas fa-broom mr-2"></i>Objectif</h3>
193
+ <p>Nettoyer le maximum de taches en 60 secondes pour marquer des points.</p>
194
+ </div>
195
+ <div class="bg-blue-700 p-4 rounded-lg">
196
+ <h3 class="font-bold text-lg mb-2"><i class="fas fa-star mr-2"></i>Points</h3>
197
+ <ul class="list-disc pl-5 space-y-1">
198
+ <li>Taches normales: 1-3 points selon la taille</li>
199
+ <li>Taches mobiles: 2-4 points (plus difficiles à attraper)</li>
200
+ <li>Bonus de combo: +1 point par niveau de combo</li>
201
+ </ul>
202
+ </div>
203
+ <div class="bg-blue-700 p-4 rounded-lg">
204
+ <h3 class="font-bold text-lg mb-2"><i class="fas fa-skull mr-2"></i>Pénalités</h3>
205
+ <ul class="list-disc pl-5 space-y-1">
206
+ <li>Taches noires: -3 points</li>
207
+ <li>Taches rouges: -5 points</li>
208
+ </ul>
209
+ </div>
210
+ <div class="bg-blue-700 p-4 rounded-lg">
211
+ <h3 class="font-bold text-lg mb-2"><i class="fas fa-bolt mr-2"></i>Combo</h3>
212
+ <p>Nettoyer plusieurs taches rapidement augmente votre combo (max x10). Le combo se réinitialise après 1 seconde sans nettoyer de tache.</p>
213
+ </div>
214
+ <div class="bg-blue-700 p-4 rounded-lg">
215
+ <h3 class="font-bold text-lg mb-2"><i class="fas fa-level-up-alt mr-2"></i>Niveaux</h3>
216
+ <p>Nettoyer 10 taches vous fait passer au niveau suivant. La difficulté augmente avec plus de taches mobiles et pénalisantes.</p>
217
+ </div>
218
+ </div>
219
+ <div class="mt-6 text-center">
220
+ <button id="start-from-rules-btn" class="btn-pulse bg-white text-blue-600 font-bold py-3 px-8 rounded-full text-lg hover:bg-blue-100 transition">
221
+ COMMENCER
222
+ </button>
223
+ </div>
224
+ </div>
225
+ </div>
226
+ </main>
227
+
228
+ <!-- Footer -->
229
+ <footer class="bg-blue-800 text-white py-3 text-center text-sm">
230
+ <p>© 2008 AJNET 31 - Défi de nettoyage expert</p>
231
+ </footer>
232
+ </div>
233
+
234
+ <script>
235
+ // Game variables
236
+ let score = 0;
237
+ let timeLeft = 60;
238
+ let level = 1;
239
+ let gameInterval;
240
+ let stainInterval;
241
+ let timeInterval;
242
+ let gameActive = false;
243
+ let stainsCleaned = 0;
244
+ let stainSpeed = 800;
245
+ let lastCleanTime = 0;
246
+ let combo = 0;
247
+ let maxCombo = 0;
248
+ let comboTimeout;
249
+ let movingStainChance = 0.5;
250
+ let penaltyStainChance = 0.25;
251
+ let stainCount = 0;
252
+ let penaltyStainCount = 0;
253
+
254
+ // DOM elements
255
+ const gameArea = document.getElementById('game-area');
256
+ const scoreDisplay = document.getElementById('score');
257
+ const timeDisplay = document.getElementById('time');
258
+ const timeBar = document.getElementById('time-bar');
259
+ const levelDisplay = document.getElementById('level');
260
+ const startScreen = document.getElementById('start-screen');
261
+ const gameOverScreen = document.getElementById('game-over');
262
+ const finalScoreDisplay = document.getElementById('final-score');
263
+ const finalLevelDisplay = document.getElementById('final-level');
264
+ const finalComboDisplay = document.getElementById('final-combo');
265
+ const startBtn = document.getElementById('start-btn');
266
+ const restartBtn = document.getElementById('restart-btn');
267
+ const shareBtn = document.getElementById('share-btn');
268
+ const comboCounter = document.getElementById('combo-counter');
269
+ const comboDisplay = document.getElementById('combo');
270
+ const rulesBtn = document.getElementById('rules-btn');
271
+ const rulesModal = document.getElementById('rules-modal');
272
+ const closeRulesBtn = document.getElementById('close-rules-btn');
273
+ const startFromRulesBtn = document.getElementById('start-from-rules-btn');
274
+
275
+ // Stain types with different colors, sizes and behaviors
276
+ const stainTypes = [
277
+ { class: 'bg-red-500', size: 'w-16 h-16', points: 1, moving: false, penalty: false },
278
+ { class: 'bg-yellow-500', size: 'w-20 h-20', points: 2, moving: false, penalty: false },
279
+ { class: 'bg-green-500', size: 'w-24 h-24', points: 3, moving: false, penalty: false },
280
+ { class: 'bg-purple-500', size: 'w-14 h-14', points: 1, moving: false, penalty: false },
281
+ { class: 'bg-pink-500', size: 'w-18 h-18', points: 2, moving: false, penalty: false },
282
+ { class: 'bg-blue-500', size: 'w-22 h-22', points: 3, moving: false, penalty: false },
283
+ { class: 'bg-red-600', size: 'w-20 h-20', points: -5, moving: true, penalty: true },
284
+ { class: 'bg-gray-800', size: 'w-24 h-24', points: -3, moving: false, penalty: true }
285
+ ];
286
+
287
+ // Initialize game
288
+ function initGame() {
289
+ score = 0;
290
+ timeLeft = 60;
291
+ level = 1;
292
+ stainsCleaned = 0;
293
+ stainSpeed = 800;
294
+ combo = 0;
295
+ maxCombo = 0;
296
+ stainCount = 0;
297
+ penaltyStainCount = 0;
298
+
299
+ updateScore();
300
+ updateTime();
301
+ updateLevel();
302
+ hideCombo();
303
+
304
+ gameArea.innerHTML = '';
305
+ }
306
+
307
+ // Start game
308
+ function startGame() {
309
+ initGame();
310
+ gameActive = true;
311
+ startScreen.classList.add('hidden');
312
+ gameOverScreen.classList.add('hidden');
313
+ rulesModal.classList.add('hidden');
314
+
315
+ // Start timers
316
+ timeInterval = setInterval(updateTimer, 1000);
317
+ stainInterval = setInterval(createStain, stainSpeed);
318
+
319
+ // Check game state every 500ms
320
+ gameInterval = setInterval(checkGameState, 500);
321
+ }
322
+
323
+ // Create a new stain (now covering the whole screen)
324
+ function createStain() {
325
+ if (!gameActive) return;
326
+
327
+ const gameAreaRect = gameArea.getBoundingClientRect();
328
+ const x = Math.random() * (gameAreaRect.width - 100);
329
+ const y = Math.random() * (gameAreaRect.height - 100);
330
+
331
+ // Determine if this should be a moving or penalty stain
332
+ let stainTypeIndex;
333
+
334
+ // Prevent too many penalty stains (max 1 penalty stain for every 3 normal stains)
335
+ if (penaltyStainCount >= Math.ceil(stainCount / 3) && Math.random() < penaltyStainChance) {
336
+ stainTypeIndex = Math.floor(Math.random() * (stainTypes.length - 2));
337
+ } else {
338
+ // Chance for moving stain (higher now)
339
+ if (Math.random() < movingStainChance) {
340
+ stainTypeIndex = Math.floor(Math.random() * (stainTypes.length - 2));
341
+ }
342
+
343
+ // Chance for penalty stain
344
+ if (Math.random() < penaltyStainChance) {
345
+ stainTypeIndex = Math.floor(Math.random() * 2) + (stainTypes.length - 2);
346
+ } else {
347
+ stainTypeIndex = Math.floor(Math.random() * (stainTypes.length - 2));
348
+ }
349
+ }
350
+
351
+ const stainType = stainTypes[stainTypeIndex];
352
+
353
+ const stain = document.createElement('div');
354
+ stain.className = `stain rounded-full absolute ${stainType.class} ${stainType.size}`;
355
+ stain.style.left = `${x}px`;
356
+ stain.style.top = `${y}px`;
357
+
358
+ // Add moving class if needed (more stains will move now)
359
+ if (stainType.moving || Math.random() < movingStainChance) {
360
+ stain.classList.add('moving-stain');
361
+ }
362
+
363
+ // Add data attributes
364
+ stain.dataset.points = stainType.points;
365
+ stain.dataset.penalty = stainType.penalty;
366
+
367
+ // Add click event
368
+ stain.addEventListener('click', cleanStain);
369
+
370
+ gameArea.appendChild(stain);
371
+ stainCount++;
372
+
373
+ // Track penalty stains
374
+ if (stainType.penalty) {
375
+ penaltyStainCount++;
376
+ }
377
+ }
378
+
379
+ // Clean stain
380
+ function cleanStain(e) {
381
+ if (!gameActive) return;
382
+
383
+ const stain = e.target;
384
+ const points = parseInt(stain.dataset.points);
385
+ const isPenalty = stain.dataset.penalty === 'true';
386
+
387
+ // Remove stain
388
+ stain.remove();
389
+ stainCount--;
390
+
391
+ // Update penalty stain count
392
+ if (isPenalty) {
393
+ penaltyStainCount = Math.max(0, penaltyStainCount - 1);
394
+ }
395
+
396
+ // Update combo
397
+ const now = Date.now();
398
+ if (now - lastCleanTime < 1000) {
399
+ combo++;
400
+ if (combo > maxCombo) maxCombo = combo;
401
+
402
+ showCombo();
403
+
404
+ clearTimeout(comboTimeout);
405
+ comboTimeout = setTimeout(resetCombo, 1000);
406
+ } else {
407
+ resetCombo();
408
+ }
409
+ lastCleanTime = now;
410
+
411
+ // Update score
412
+ if (isPenalty) {
413
+ score += points;
414
+ showPenaltyEffect(stain, points);
415
+ } else {
416
+ const bonus = combo > 0 ? Math.floor(combo / 2) : 0;
417
+ score += points + bonus;
418
+ stainsCleaned++;
419
+ showComboEffect(stain, points + bonus);
420
+ }
421
+
422
+ updateScore();
423
+
424
+ // Check level up
425
+ if (stainsCleaned >= level * 10) {
426
+ levelUp();
427
+ }
428
+ }
429
+
430
+ // Show combo effect
431
+ function showComboEffect(element, points) {
432
+ const rect = element.getBoundingClientRect();
433
+ const gameAreaRect = gameArea.getBoundingClientRect();
434
+
435
+ const effect = document.createElement('div');
436
+ effect.className = 'combo-effect';
437
+ effect.textContent = `+${points}`;
438
+ effect.style.left = `${rect.left - gameAreaRect.left}px`;
439
+ effect.style.top = `${rect.top - gameAreaRect.top}px`;
440
+
441
+ gameArea.appendChild(effect);
442
+
443
+ setTimeout(() => {
444
+ effect.remove();
445
+ }, 1500);
446
+ }
447
+
448
+ // Show penalty effect
449
+ function showPenaltyEffect(element, points) {
450
+ const rect = element.getBoundingClientRect();
451
+ const gameAreaRect = gameArea.getBoundingClientRect();
452
+
453
+ const effect = document.createElement('div');
454
+ effect.className = 'penalty-effect';
455
+ effect.textContent = `${points}`;
456
+ effect.style.left = `${rect.left - gameAreaRect.left}px`;
457
+ effect.style.top = `${rect.top - gameAreaRect.top}px`;
458
+
459
+ gameArea.appendChild(effect);
460
+
461
+ setTimeout(() => {
462
+ effect.remove();
463
+ }, 1500);
464
+ }
465
+
466
+ // Show combo counter
467
+ function showCombo() {
468
+ comboCounter.classList.remove('hidden');
469
+ comboDisplay.textContent = combo;
470
+ }
471
+
472
+ // Hide combo counter
473
+ function hideCombo() {
474
+ comboCounter.classList.add('hidden');
475
+ }
476
+
477
+ // Reset combo
478
+ function resetCombo() {
479
+ combo = 0;
480
+ hideCombo();
481
+ }
482
+
483
+ // Level up
484
+ function levelUp() {
485
+ level++;
486
+ stainsCleaned = 0;
487
+
488
+ // Increase difficulty
489
+ stainSpeed = Math.max(stainSpeed - 100, 300); // Faster spawn (min 300ms)
490
+ movingStainChance = Math.min(movingStainChance + 0.05, 0.8); // More moving stains
491
+ penaltyStainChance = Math.min(penaltyStainChance + 0.02, 0.4); // More penalty stains
492
+
493
+ updateLevel();
494
+
495
+ // Show level up effect
496
+ const levelUpEffect = document.createElement('div');
497
+ levelUpEffect.className = 'absolute inset-0 flex items-center justify-center';
498
+ levelUpEffect.innerHTML = `
499
+ <div class="bg-blue-600 bg-opacity-80 text-white text-4xl font-bold p-8 rounded-xl animate-pulse">
500
+ Niveau ${level}!
501
+ </div>
502
+ `;
503
+ gameArea.appendChild(levelUpEffect);
504
+
505
+ setTimeout(() => {
506
+ levelUpEffect.remove();
507
+ }, 1500);
508
+ }
509
+
510
+ // Update timer
511
+ function updateTimer() {
512
+ timeLeft--;
513
+ updateTime();
514
+
515
+ if (timeLeft <= 0) {
516
+ endGame();
517
+ }
518
+ }
519
+
520
+ // Update time display
521
+ function updateTime() {
522
+ timeDisplay.textContent = timeLeft;
523
+ timeBar.style.width = `${(timeLeft / 60) * 100}%`;
524
+
525
+ if (timeLeft <= 10) {
526
+ timeBar.classList.remove('bg-blue-600');
527
+ timeBar.classList.add('bg-red-500');
528
+ timeDisplay.classList.add('text-red-500');
529
+ } else {
530
+ timeBar.classList.remove('bg-red-500');
531
+ timeBar.classList.add('bg-blue-600');
532
+ timeDisplay.classList.remove('text-red-500');
533
+ }
534
+ }
535
+
536
+ // Update score display
537
+ function updateScore() {
538
+ scoreDisplay.textContent = score;
539
+ }
540
+
541
+ // Update level display
542
+ function updateLevel() {
543
+ levelDisplay.textContent = level;
544
+ }
545
+
546
+ // Check game state
547
+ function checkGameState() {
548
+ if (timeLeft <= 0) {
549
+ endGame();
550
+ }
551
+ }
552
+
553
+ // End game
554
+ function endGame() {
555
+ gameActive = false;
556
+
557
+ clearInterval(timeInterval);
558
+ clearInterval(stainInterval);
559
+ clearInterval(gameInterval);
560
+ clearTimeout(comboTimeout);
561
+
562
+ finalScoreDisplay.textContent = score;
563
+ finalLevelDisplay.textContent = level;
564
+ finalComboDisplay.textContent = maxCombo;
565
+ gameOverScreen.classList.remove('hidden');
566
+ }
567
+
568
+ // Event listeners
569
+ startBtn.addEventListener('click', startGame);
570
+ restartBtn.addEventListener('click', startGame);
571
+ shareBtn.addEventListener('click', () => {
572
+ alert(`Partagez votre score de ${score} points (Niveau ${level}) avec vos amis!`);
573
+ });
574
+
575
+ rulesBtn.addEventListener('click', () => {
576
+ rulesModal.classList.remove('hidden');
577
+ });
578
+
579
+ closeRulesBtn.addEventListener('click', () => {
580
+ rulesModal.classList.add('hidden');
581
+ });
582
+
583
+ startFromRulesBtn.addEventListener('click', startGame);
584
+
585
+ // Initialize game on load
586
+ initGame();
587
+ </script>
588
+ <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=johanpautrel/ajnet-31" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
589
+ </html>