|
<!DOCTYPE html> |
|
<html lang="fr"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>AJNET 31 - Jeu de Nettoyage Expert</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
<style> |
|
@keyframes fadeIn { |
|
from { opacity: 0; } |
|
to { opacity: 1; } |
|
} |
|
|
|
@keyframes pulse { |
|
0% { transform: scale(1); } |
|
50% { transform: scale(1.05); } |
|
100% { transform: scale(1); } |
|
} |
|
|
|
@keyframes shake { |
|
0%, 100% { transform: translateX(0); } |
|
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); } |
|
20%, 40%, 60%, 80% { transform: translateX(5px); } |
|
} |
|
|
|
@keyframes float { |
|
0%, 100% { transform: translateY(0); } |
|
50% { transform: translateY(-10px); } |
|
} |
|
|
|
.stain { |
|
animation: fadeIn 0.3s ease-in; |
|
transition: transform 0.2s; |
|
cursor: pointer; |
|
position: absolute; |
|
} |
|
|
|
.stain:hover { |
|
transform: scale(0.95); |
|
} |
|
|
|
.moving-stain { |
|
animation: moveRandom 4s linear infinite; |
|
} |
|
|
|
@keyframes moveRandom { |
|
0% { |
|
transform: translate(0, 0); |
|
left: var(--start-x); |
|
top: var(--start-y); |
|
} |
|
25% { |
|
transform: translate(calc(var(--move-x1) * 1px), calc(var(--move-y1) * 1px)); |
|
} |
|
50% { |
|
transform: translate(calc(var(--move-x2) * 1px), calc(var(--move-y2) * 1px)); |
|
} |
|
75% { |
|
transform: translate(calc(var(--move-x3) * 1px), calc(var(--move-y3) * 1px)); |
|
} |
|
100% { |
|
transform: translate(0, 0); |
|
} |
|
} |
|
|
|
.game-container { |
|
background-image: linear-gradient(to bottom, #f0f9ff, #e0f2fe); |
|
position: relative; |
|
overflow: hidden; |
|
height: calc(100vh - 120px); |
|
} |
|
|
|
.progress-bar { |
|
transition: width 0.3s ease-out; |
|
} |
|
|
|
.modal { |
|
animation: fadeIn 0.3s ease-out; |
|
} |
|
|
|
.btn-pulse { |
|
animation: pulse 1.5s infinite; |
|
} |
|
|
|
.shake { |
|
animation: shake 0.5s; |
|
} |
|
|
|
.combo-effect { |
|
position: absolute; |
|
font-size: 1.5rem; |
|
font-weight: bold; |
|
color: #3b82f6; |
|
opacity: 0; |
|
animation: fadeIn 0.5s forwards, float 1s forwards; |
|
} |
|
|
|
.penalty-effect { |
|
position: absolute; |
|
font-size: 1.5rem; |
|
font-weight: bold; |
|
color: #ef4444; |
|
opacity: 0; |
|
animation: fadeIn 0.5s forwards, shake 0.5s forwards; |
|
} |
|
|
|
.rules-modal { |
|
max-height: 80vh; |
|
overflow-y: auto; |
|
} |
|
</style> |
|
</head> |
|
<body class="bg-gray-100 font-sans"> |
|
<div class="min-h-screen flex flex-col"> |
|
|
|
<header class="bg-blue-600 text-white py-4 shadow-lg"> |
|
<div class="container mx-auto px-4 flex justify-between items-center"> |
|
<div class="flex items-center space-x-2"> |
|
<i class="fas fa-broom text-2xl"></i> |
|
<h1 class="text-2xl font-bold">AJNET 31</h1> |
|
</div> |
|
<div class="flex items-center space-x-4"> |
|
<button id="rules-btn" class="bg-blue-800 px-3 py-1 rounded-full font-bold text-sm hover:bg-blue-700 transition"> |
|
<i class="fas fa-info-circle mr-1"></i>Règles |
|
</button> |
|
<div id="combo-counter" class="hidden bg-blue-800 px-3 py-1 rounded-full font-bold text-sm"> |
|
Combo x<span id="combo">0</span> |
|
</div> |
|
<div id="score-display" class="bg-blue-800 px-4 py-2 rounded-full font-bold"> |
|
Score: <span id="score">0</span> |
|
</div> |
|
</div> |
|
</div> |
|
</header> |
|
|
|
|
|
<main class="flex-grow game-container relative overflow-hidden"> |
|
<div class="absolute top-4 left-4 bg-blue-100 bg-opacity-80 p-2 rounded-lg shadow"> |
|
<div class="flex items-center space-x-2"> |
|
<i class="fas fa-clock text-blue-600"></i> |
|
<span id="time">60</span>s |
|
</div> |
|
<div class="mt-2 w-full bg-gray-200 rounded-full h-2.5"> |
|
<div id="time-bar" class="progress-bar bg-blue-600 h-2.5 rounded-full" style="width: 100%"></div> |
|
</div> |
|
</div> |
|
|
|
<div class="absolute top-4 right-4 bg-blue-100 bg-opacity-80 p-2 rounded-lg shadow"> |
|
<div class="flex items-center space-x-2"> |
|
<i class="fas fa-tachometer-alt text-blue-600"></i> |
|
Niveau: <span id="level">1</span> |
|
</div> |
|
</div> |
|
|
|
<div id="game-area" class="w-full h-full relative"></div> |
|
|
|
|
|
<div id="start-screen" class="absolute inset-0 bg-blue-600 bg-opacity-90 flex flex-col items-center justify-center text-white"> |
|
<div class="text-center max-w-md px-6"> |
|
<i class="fas fa-broom text-6xl mb-6"></i> |
|
<h2 class="text-4xl font-bold mb-4">AJNET 31</h2> |
|
<p class="text-xl mb-6">Mode Expert: Taches mobiles, combo et pénalités!</p> |
|
<div class="bg-blue-800 p-4 rounded-lg mb-6 text-left"> |
|
<p class="mb-2"><i class="fas fa-running mr-2"></i> Taches mobiles apparaissent</p> |
|
<p class="mb-2"><i class="fas fa-bolt mr-2"></i> Combo pour bonus de points</p> |
|
<p class="mb-2"><i class="fas fa-skull mr-2"></i> Taches spéciales pénalisantes</p> |
|
</div> |
|
<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"> |
|
DÉFI EXPERT |
|
</button> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="game-over" class="modal absolute inset-0 bg-blue-600 bg-opacity-90 hidden flex-col items-center justify-center text-white"> |
|
<div class="text-center max-w-md px-6"> |
|
<i class="fas fa-award text-6xl mb-6"></i> |
|
<h2 class="text-4xl font-bold mb-4">Performance</h2> |
|
<div class="bg-blue-800 p-6 rounded-xl mb-6"> |
|
<p class="text-5xl font-bold mb-2" id="final-score">0</p> |
|
<p class="text-lg">points</p> |
|
<p class="mt-4"><i class="fas fa-trophy mr-2"></i>Niveau atteint: <span id="final-level">1</span></p> |
|
<p><i class="fas fa-bolt mr-2"></i>Combo max: x<span id="final-combo">0</span></p> |
|
</div> |
|
<div class="flex space-x-4"> |
|
<button id="restart-btn" class="bg-white text-blue-600 font-bold py-3 px-6 rounded-full hover:bg-blue-100 transition"> |
|
<i class="fas fa-redo mr-2"></i>Rejouer |
|
</button> |
|
<button id="share-btn" class="bg-blue-800 text-white font-bold py-3 px-6 rounded-full hover:bg-blue-700 transition"> |
|
<i class="fas fa-share-alt mr-2"></i>Partager |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="rules-modal" class="modal absolute inset-0 bg-blue-600 bg-opacity-90 hidden flex-col items-center justify-center text-white"> |
|
<div class="rules-modal bg-blue-800 p-6 rounded-xl max-w-md mx-4"> |
|
<div class="flex justify-between items-center mb-4"> |
|
<h2 class="text-2xl font-bold"><i class="fas fa-book mr-2"></i>Règles du Jeu</h2> |
|
<button id="close-rules-btn" class="text-white hover:text-blue-200 text-2xl"> |
|
<i class="fas fa-times"></i> |
|
</button> |
|
</div> |
|
<div class="space-y-4"> |
|
<div class="bg-blue-700 p-4 rounded-lg"> |
|
<h3 class="font-bold text-lg mb-2"><i class="fas fa-broom mr-2"></i>Objectif</h3> |
|
<p>Nettoyer le maximum de taches en 60 secondes pour marquer des points.</p> |
|
</div> |
|
<div class="bg-blue-700 p-4 rounded-lg"> |
|
<h3 class="font-bold text-lg mb-2"><i class="fas fa-star mr-2"></i>Points</h3> |
|
<ul class="list-disc pl-5 space-y-1"> |
|
<li>Taches normales: 1-3 points selon la taille</li> |
|
<li>Taches mobiles: 2-4 points (plus difficiles à attraper)</li> |
|
<li>Bonus de combo: +1 point par niveau de combo</li> |
|
</ul> |
|
</div> |
|
<div class="bg-blue-700 p-4 rounded-lg"> |
|
<h3 class="font-bold text-lg mb-2"><i class="fas fa-skull mr-2"></i>Pénalités</h3> |
|
<ul class="list-disc pl-5 space-y-1"> |
|
<li>Taches noires: -3 points</li> |
|
<li>Taches rouges: -5 points</li> |
|
</ul> |
|
</div> |
|
<div class="bg-blue-700 p-4 rounded-lg"> |
|
<h3 class="font-bold text-lg mb-2"><i class="fas fa-bolt mr-2"></i>Combo</h3> |
|
<p>Nettoyer plusieurs taches rapidement augmente votre combo (max x10). Le combo se réinitialise après 1 seconde sans nettoyer de tache.</p> |
|
</div> |
|
<div class="bg-blue-700 p-4 rounded-lg"> |
|
<h3 class="font-bold text-lg mb-2"><i class="fas fa-level-up-alt mr-2"></i>Niveaux</h3> |
|
<p>Nettoyer 10 taches vous fait passer au niveau suivant. La difficulté augmente avec plus de taches mobiles et pénalisantes.</p> |
|
</div> |
|
</div> |
|
<div class="mt-6 text-center"> |
|
<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"> |
|
COMMENCER |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</main> |
|
|
|
|
|
<footer class="bg-blue-800 text-white py-3 text-center text-sm"> |
|
<p>© 2008 AJNET 31 - Défi de nettoyage expert</p> |
|
</footer> |
|
</div> |
|
|
|
<script> |
|
|
|
let score = 0; |
|
let timeLeft = 60; |
|
let level = 1; |
|
let gameInterval; |
|
let stainInterval; |
|
let timeInterval; |
|
let gameActive = false; |
|
let stainsCleaned = 0; |
|
let stainSpeed = 800; |
|
let lastCleanTime = 0; |
|
let combo = 0; |
|
let maxCombo = 0; |
|
let comboTimeout; |
|
let movingStainChance = 0.5; |
|
let penaltyStainChance = 0.25; |
|
let stainCount = 0; |
|
let penaltyStainCount = 0; |
|
|
|
|
|
const gameArea = document.getElementById('game-area'); |
|
const scoreDisplay = document.getElementById('score'); |
|
const timeDisplay = document.getElementById('time'); |
|
const timeBar = document.getElementById('time-bar'); |
|
const levelDisplay = document.getElementById('level'); |
|
const startScreen = document.getElementById('start-screen'); |
|
const gameOverScreen = document.getElementById('game-over'); |
|
const finalScoreDisplay = document.getElementById('final-score'); |
|
const finalLevelDisplay = document.getElementById('final-level'); |
|
const finalComboDisplay = document.getElementById('final-combo'); |
|
const startBtn = document.getElementById('start-btn'); |
|
const restartBtn = document.getElementById('restart-btn'); |
|
const shareBtn = document.getElementById('share-btn'); |
|
const comboCounter = document.getElementById('combo-counter'); |
|
const comboDisplay = document.getElementById('combo'); |
|
const rulesBtn = document.getElementById('rules-btn'); |
|
const rulesModal = document.getElementById('rules-modal'); |
|
const closeRulesBtn = document.getElementById('close-rules-btn'); |
|
const startFromRulesBtn = document.getElementById('start-from-rules-btn'); |
|
|
|
|
|
const stainTypes = [ |
|
{ class: 'bg-red-500', size: 'w-16 h-16', points: 1, moving: false, penalty: false }, |
|
{ class: 'bg-yellow-500', size: 'w-20 h-20', points: 2, moving: false, penalty: false }, |
|
{ class: 'bg-green-500', size: 'w-24 h-24', points: 3, moving: false, penalty: false }, |
|
{ class: 'bg-purple-500', size: 'w-14 h-14', points: 1, moving: false, penalty: false }, |
|
{ class: 'bg-pink-500', size: 'w-18 h-18', points: 2, moving: false, penalty: false }, |
|
{ class: 'bg-blue-500', size: 'w-22 h-22', points: 3, moving: false, penalty: false }, |
|
{ class: 'bg-red-600', size: 'w-20 h-20', points: -5, moving: true, penalty: true }, |
|
{ class: 'bg-gray-800', size: 'w-24 h-24', points: -3, moving: false, penalty: true } |
|
]; |
|
|
|
|
|
function initGame() { |
|
score = 0; |
|
timeLeft = 60; |
|
level = 1; |
|
stainsCleaned = 0; |
|
stainSpeed = 800; |
|
combo = 0; |
|
maxCombo = 0; |
|
stainCount = 0; |
|
penaltyStainCount = 0; |
|
|
|
updateScore(); |
|
updateTime(); |
|
updateLevel(); |
|
hideCombo(); |
|
|
|
gameArea.innerHTML = ''; |
|
} |
|
|
|
|
|
function startGame() { |
|
initGame(); |
|
gameActive = true; |
|
startScreen.classList.add('hidden'); |
|
gameOverScreen.classList.add('hidden'); |
|
rulesModal.classList.add('hidden'); |
|
|
|
|
|
timeInterval = setInterval(updateTimer, 1000); |
|
stainInterval = setInterval(createStain, stainSpeed); |
|
|
|
|
|
gameInterval = setInterval(checkGameState, 500); |
|
} |
|
|
|
|
|
function createStain() { |
|
if (!gameActive) return; |
|
|
|
const gameAreaRect = gameArea.getBoundingClientRect(); |
|
const maxX = gameAreaRect.width - 100; |
|
const maxY = gameAreaRect.height - 100; |
|
|
|
|
|
const startX = Math.random() * maxX; |
|
const startY = Math.random() * (maxY - 100) + 50; |
|
|
|
|
|
let stainTypeIndex; |
|
|
|
if (penaltyStainCount >= Math.ceil(stainCount / 3) && Math.random() < penaltyStainChance) { |
|
stainTypeIndex = Math.floor(Math.random() * (stainTypes.length - 2)); |
|
} else { |
|
if (Math.random() < movingStainChance) { |
|
stainTypeIndex = Math.floor(Math.random() * (stainTypes.length - 2)); |
|
} |
|
|
|
if (Math.random() < penaltyStainChance) { |
|
stainTypeIndex = Math.floor(Math.random() * 2) + (stainTypes.length - 2); |
|
} else { |
|
stainTypeIndex = Math.floor(Math.random() * (stainTypes.length - 2)); |
|
} |
|
} |
|
|
|
const stainType = stainTypes[stainTypeIndex]; |
|
|
|
const stain = document.createElement('div'); |
|
stain.className = `stain rounded-full ${stainType.class} ${stainType.size}`; |
|
stain.style.setProperty('--start-x', `${startX}px`); |
|
stain.style.setProperty('--start-y', `${startY}px`); |
|
|
|
|
|
const moveX1 = (Math.random() * maxX - startX) * 0.5; |
|
const moveY1 = (Math.random() * (maxY - 100) - startY) * 0.5; |
|
const moveX2 = (Math.random() * maxX - startX) * 0.5; |
|
const moveY2 = (Math.random() * (maxY - 100) - startY) * 0.5; |
|
const moveX3 = (Math.random() * maxX - startX) * 0.5; |
|
const moveY3 = (Math.random() * (maxY - 100) - startY) * 0.5; |
|
|
|
stain.style.setProperty('--move-x1', moveX1); |
|
stain.style.setProperty('--move-y1', moveY1); |
|
stain.style.setProperty('--move-x2', moveX2); |
|
stain.style.setProperty('--move-y2', moveY2); |
|
stain.style.setProperty('--move-x3', moveX3); |
|
stain.style.setProperty('--move-y3', moveY3); |
|
|
|
|
|
if (stainType.moving || Math.random() < movingStainChance) { |
|
stain.classList.add('moving-stain'); |
|
|
|
stain.style.animationDuration = `${3 + Math.random() * 2}s`; |
|
} |
|
|
|
|
|
stain.dataset.points = stainType.points; |
|
stain.dataset.penalty = stainType.penalty; |
|
|
|
|
|
stain.style.left = `${startX}px`; |
|
stain.style.top = `${startY}px`; |
|
|
|
|
|
stain.addEventListener('click', cleanStain); |
|
|
|
gameArea.appendChild(stain); |
|
stainCount++; |
|
|
|
if (stainType.penalty) { |
|
penaltyStainCount++; |
|
} |
|
} |
|
|
|
|
|
function cleanStain(e) { |
|
if (!gameActive) return; |
|
|
|
const stain = e.target; |
|
const points = parseInt(stain.dataset.points); |
|
const isPenalty = stain.dataset.penalty === 'true'; |
|
|
|
stain.remove(); |
|
stainCount--; |
|
|
|
if (isPenalty) { |
|
penaltyStainCount = Math.max(0, penaltyStainCount - 1); |
|
} |
|
|
|
const now = Date.now(); |
|
if (now - lastCleanTime < 1000) { |
|
combo++; |
|
if (combo > maxCombo) maxCombo = combo; |
|
|
|
showCombo(); |
|
|
|
clearTimeout(comboTimeout); |
|
comboTimeout = setTimeout(resetCombo, 1000); |
|
} else { |
|
resetCombo(); |
|
} |
|
lastCleanTime = now; |
|
|
|
if (isPenalty) { |
|
score += points; |
|
showPenaltyEffect(stain, points); |
|
} else { |
|
const bonus = combo > 0 ? Math.floor(combo / 2) : 0; |
|
score += points + bonus; |
|
stainsCleaned++; |
|
showComboEffect(stain, points + bonus); |
|
} |
|
|
|
updateScore(); |
|
|
|
if (stainsCleaned >= level * 10) { |
|
levelUp(); |
|
} |
|
} |
|
|
|
|
|
function showComboEffect(element, points) { |
|
const rect = element.getBoundingClientRect(); |
|
const gameAreaRect = gameArea.getBoundingClientRect(); |
|
|
|
const effect = document.createElement('div'); |
|
effect.className = 'combo-effect'; |
|
effect.textContent = `+${points}`; |
|
effect.style.left = `${rect.left - gameAreaRect.left}px`; |
|
effect.style.top = `${rect.top - gameAreaRect.top}px`; |
|
|
|
gameArea.appendChild(effect); |
|
|
|
setTimeout(() => { |
|
effect.remove(); |
|
}, 1500); |
|
} |
|
|
|
|
|
function showPenaltyEffect(element, points) { |
|
const rect = element.getBoundingClientRect(); |
|
const gameAreaRect = gameArea.getBoundingClientRect(); |
|
|
|
const effect = document.createElement('div'); |
|
effect.className = 'penalty-effect'; |
|
effect.textContent = `${points}`; |
|
effect.style.left = `${rect.left - gameAreaRect.left}px`; |
|
effect.style.top = `${rect.top - gameAreaRect.top}px`; |
|
|
|
gameArea.appendChild(effect); |
|
|
|
setTimeout(() => { |
|
effect.remove(); |
|
}, 1500); |
|
} |
|
|
|
|
|
function showCombo() { |
|
comboCounter.classList.remove('hidden'); |
|
comboDisplay.textContent = combo; |
|
} |
|
|
|
|
|
function hideCombo() { |
|
comboCounter.classList.add('hidden'); |
|
} |
|
|
|
|
|
function resetCombo() { |
|
combo = 0; |
|
hideCombo(); |
|
} |
|
|
|
|
|
function levelUp() { |
|
level++; |
|
stainsCleaned = 0; |
|
|
|
stainSpeed = Math.max(stainSpeed - 100, 300); |
|
movingStainChance = Math.min(movingStainChance + 0.05, 0.8); |
|
penaltyStainChance = Math.min(penaltyStainChance + 0.02, 0.4); |
|
|
|
updateLevel(); |
|
|
|
const levelUpEffect = document.createElement('div'); |
|
levelUpEffect.className = 'absolute inset-0 flex items-center justify-center'; |
|
levelUpEffect.innerHTML = ` |
|
<div class="bg-blue-600 bg-opacity-80 text-white text-4xl font-bold p-8 rounded-xl animate-pulse"> |
|
Niveau ${level}! |
|
</div> |
|
`; |
|
gameArea.appendChild(levelUpEffect); |
|
|
|
setTimeout(() => { |
|
levelUpEffect.remove(); |
|
}, 1500); |
|
} |
|
|
|
|
|
function updateTimer() { |
|
timeLeft--; |
|
updateTime(); |
|
|
|
if (timeLeft <= 0) { |
|
endGame(); |
|
} |
|
} |
|
|
|
|
|
function updateTime() { |
|
timeDisplay.textContent = timeLeft; |
|
timeBar.style.width = `${(timeLeft / 60) * 100}%`; |
|
|
|
if (timeLeft <= 10) { |
|
timeBar.classList.remove('bg-blue-600'); |
|
timeBar.classList.add('bg-red-500'); |
|
timeDisplay.classList.add('text-red-500'); |
|
} else { |
|
timeBar.classList.remove('bg-red-500'); |
|
timeBar.classList.add('bg-blue-600'); |
|
timeDisplay.classList.remove('text-red-500'); |
|
} |
|
} |
|
|
|
|
|
function updateScore() { |
|
scoreDisplay.textContent = score; |
|
} |
|
|
|
|
|
function updateLevel() { |
|
levelDisplay.textContent = level; |
|
} |
|
|
|
|
|
function checkGameState() { |
|
if (timeLeft <= 0) { |
|
endGame(); |
|
} |
|
} |
|
|
|
|
|
function endGame() { |
|
gameActive = false; |
|
|
|
clearInterval(timeInterval); |
|
clearInterval(stainInterval); |
|
clearInterval(gameInterval); |
|
clearTimeout(comboTimeout); |
|
|
|
finalScoreDisplay.textContent = score; |
|
finalLevelDisplay.textContent = level; |
|
finalComboDisplay.textContent = maxCombo; |
|
gameOverScreen.classList.remove('hidden'); |
|
} |
|
|
|
|
|
startBtn.addEventListener('click', startGame); |
|
restartBtn.addEventListener('click', startGame); |
|
shareBtn.addEventListener('click', () => { |
|
alert(`Partagez votre score de ${score} points (Niveau ${level}) avec vos amis!`); |
|
}); |
|
|
|
rulesBtn.addEventListener('click', () => { |
|
rulesModal.classList.remove('hidden'); |
|
}); |
|
|
|
closeRulesBtn.addEventListener('click', () => { |
|
rulesModal.classList.add('hidden'); |
|
}); |
|
|
|
startFromRulesBtn.addEventListener('click', startGame); |
|
|
|
|
|
initGame(); |
|
</script> |
|
<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/ajnet31up" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
</html> |