Download index.html from JjpieRazorwing2/anycoder-55fb0874: direct link, hf CLI and curl.
- Browser
- Download file 39.2 kB
-
https://huggingface.co/spaces/JjpieRazorwing2/anycoder-55fb0874/resolve/main/index.html
- Command line
-
hf download hf://spaces/JjpieRazorwing2/anycoder-55fb0874/index.html
-
curl -L -o index.html https://huggingface.co/spaces/JjpieRazorwing2/anycoder-55fb0874/resolve/main/index.html
39.2 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <title>NEON SURVIVOR - Cyberpunk Zombie Survival</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Rajdhani:wght@300;500;700&display=swap" rel="stylesheet"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --neon-cyan: #00f0ff; | |
| --neon-pink: #ff00ff; | |
| --neon-green: #39ff14; | |
| --neon-red: #ff073a; | |
| --neon-yellow: #ffff00; | |
| --dark-bg: #0a0a1a; | |
| --panel-bg: rgba(10, 10, 30, 0.92); | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| touch-action: none; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| body { | |
| background: var(--dark-bg); | |
| font-family: 'Rajdhani', sans-serif; | |
| overflow: hidden; | |
| user-select: none; | |
| -webkit-user-select: none; | |
| width: 100vw; | |
| height: 100vh; | |
| } | |
| canvas { | |
| display: block; | |
| image-rendering: pixelated; | |
| } | |
| /* CRT Scanline Effect */ | |
| .crt-overlay { | |
| position: fixed; | |
| inset: 0; | |
| pointer-events: none; | |
| z-index: 9999; | |
| background: repeating-linear-gradient( | |
| 0deg, | |
| rgba(0, 0, 0, 0.03) 0px, | |
| rgba(0, 0, 0, 0.03) 1px, | |
| transparent 1px, | |
| transparent 2px | |
| ); | |
| } | |
| .crt-overlay::after { | |
| content: ''; | |
| position: absolute; | |
| inset: 0; | |
| background: radial-gradient(ellipse at center, transparent 60%, rgba(0, 0, 0, 0.4) 100%); | |
| } | |
| /* Neon Glow Utilities */ | |
| .neon-text-cyan { | |
| color: var(--neon-cyan); | |
| text-shadow: 0 0 10px var(--neon-cyan), 0 0 20px var(--neon-cyan), 0 0 40px var(--neon-cyan); | |
| } | |
| .neon-text-pink { | |
| color: var(--neon-pink); | |
| text-shadow: 0 0 10px var(--neon-pink), 0 0 20px var(--neon-pink); | |
| } | |
| .neon-text-green { | |
| color: var(--neon-green); | |
| text-shadow: 0 0 10px var(--neon-green), 0 0 20px var(--neon-green); | |
| } | |
| .neon-text-red { | |
| color: var(--neon-red); | |
| text-shadow: 0 0 10px var(--neon-red), 0 0 20px var(--neon-red); | |
| } | |
| .neon-box { | |
| border: 2px solid var(--neon-cyan); | |
| box-shadow: 0 0 10px var(--neon-cyan), inset 0 0 10px rgba(0, 240, 255, 0.1); | |
| } | |
| .neon-box-pink { | |
| border: 2px solid var(--neon-pink); | |
| box-shadow: 0 0 10px var(--neon-pink), inset 0 0 10px rgba(255, 0, 255, 0.1); | |
| } | |
| /* UI Animations */ | |
| @keyframes glitch { | |
| 0%, 100% { transform: translate(0); } | |
| 20% { transform: translate(-2px, 2px); } | |
| 40% { transform: translate(-2px, -2px); } | |
| 60% { transform: translate(2px, 2px); } | |
| 80% { transform: translate(2px, -2px); } | |
| } | |
| .glitch { | |
| animation: glitch 0.3s ease-in-out; | |
| } | |
| @keyframes pulse-glow { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0.6; } | |
| } | |
| .pulse-glow { | |
| animation: pulse-glow 2s ease-in-out infinite; | |
| } | |
| @keyframes float { | |
| 0%, 100% { transform: translateY(0); } | |
| 50% { transform: translateY(-10px); } | |
| } | |
| .float { | |
| animation: float 3s ease-in-out infinite; | |
| } | |
| @keyframes scan-line { | |
| 0% { top: -5%; } | |
| 100% { top: 105%; } | |
| } | |
| .scan-line { | |
| position: absolute; | |
| left: 0; | |
| right: 0; | |
| height: 3px; | |
| background: linear-gradient(90deg, transparent, var(--neon-cyan), transparent); | |
| animation: scan-line 4s linear infinite; | |
| opacity: 0.5; | |
| } | |
| /* Progress Bars */ | |
| .hp-bar { | |
| height: 6px; | |
| background: #333; | |
| border-radius: 3px; | |
| overflow: hidden; | |
| } | |
| .hp-fill { | |
| height: 100%; | |
| background: linear-gradient(90deg, var(--neon-red), var(--neon-pink)); | |
| transition: width 0.3s ease; | |
| box-shadow: 0 0 8px var(--neon-red); | |
| } | |
| .xp-bar { | |
| height: 4px; | |
| background: #222; | |
| border-radius: 2px; | |
| overflow: hidden; | |
| } | |
| .xp-fill { | |
| height: 100%; | |
| background: linear-gradient(90deg, var(--neon-cyan), var(--neon-green)); | |
| transition: width 0.3s ease; | |
| box-shadow: 0 0 6px var(--neon-cyan); | |
| } | |
| /* Buttons */ | |
| .neon-btn { | |
| position: relative; | |
| padding: 14px 36px; | |
| font-family: 'Orbitron', sans-serif; | |
| font-size: 14px; | |
| font-weight: 700; | |
| text-transform: uppercase; | |
| letter-spacing: 3px; | |
| color: var(--neon-cyan); | |
| background: transparent; | |
| border: 2px solid var(--neon-cyan); | |
| cursor: pointer; | |
| overflow: hidden; | |
| transition: all 0.3s ease; | |
| } | |
| .neon-btn::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: -100%; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient(90deg, transparent, rgba(0, 240, 255, 0.3), transparent); | |
| transition: left 0.5s ease; | |
| } | |
| .neon-btn:hover::before { | |
| left: 100%; | |
| } | |
| .neon-btn:hover { | |
| background: rgba(0, 240, 255, 0.1); | |
| box-shadow: 0 0 20px var(--neon-cyan), inset 0 0 20px rgba(0, 240, 255, 0.1); | |
| transform: scale(1.05); | |
| } | |
| .neon-btn-pink { | |
| color: var(--neon-pink); | |
| border-color: var(--neon-pink); | |
| } | |
| .neon-btn-pink::before { | |
| background: linear-gradient(90deg, transparent, rgba(255, 0, 255, 0.3), transparent); | |
| } | |
| .neon-btn-pink:hover { | |
| background: rgba(255, 0, 255, 0.1); | |
| box-shadow: 0 0 20px var(--neon-pink), inset 0 0 20px rgba(255, 0, 255, 0.1); | |
| } | |
| /* Screens */ | |
| .screen { | |
| position: fixed; | |
| inset: 0; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 100; | |
| transition: opacity 0.5s ease, transform 0.5s ease; | |
| } | |
| .screen.hidden { | |
| opacity: 0; | |
| pointer-events: none; | |
| transform: scale(1.1); | |
| } | |
| /* HUD */ | |
| .hud-panel { | |
| background: var(--panel-bg); | |
| border: 1px solid rgba(0, 240, 255, 0.3); | |
| border-radius: 8px; | |
| padding: 8px 14px; | |
| backdrop-filter: blur(10px); | |
| } | |
| /* Skill Cards */ | |
| .skill-card { | |
| background: rgba(10, 10, 30, 0.9); | |
| border: 2px solid rgba(0, 240, 255, 0.3); | |
| border-radius: 12px; | |
| padding: 20px; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .skill-card::before { | |
| content: ''; | |
| position: absolute; | |
| inset: 0; | |
| background: linear-gradient(135deg, transparent 40%, rgba(0, 240, 255, 0.1) 100%); | |
| opacity: 0; | |
| transition: opacity 0.3s; | |
| } | |
| .skill-card:hover::before { | |
| opacity: 1; | |
| } | |
| .skill-card:hover { | |
| border-color: var(--neon-cyan); | |
| box-shadow: 0 0 20px rgba(0, 240, 255, 0.2); | |
| transform: translateY(-4px); | |
| } | |
| .skill-card.selected { | |
| border-color: var(--neon-green); | |
| box-shadow: 0 0 30px rgba(57, 255, 20, 0.3); | |
| } | |
| /* Virtual Joystick */ | |
| .joystick-zone { | |
| position: fixed; | |
| bottom: 80px; | |
| left: 80px; | |
| width: 140px; | |
| height: 140px; | |
| z-index: 50; | |
| } | |
| .joystick-base { | |
| position: absolute; | |
| width: 120px; | |
| height: 120px; | |
| border: 2px solid rgba(0, 240, 255, 0.3); | |
| border-radius: 50%; | |
| background: rgba(0, 240, 255, 0.05); | |
| } | |
| .joystick-stick { | |
| position: absolute; | |
| width: 50px; | |
| height: 50px; | |
| background: var(--neon-cyan); | |
| border-radius: 50%; | |
| box-shadow: 0 0 20px var(--neon-cyan); | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| transition: none; | |
| } | |
| /* Mobile Controls */ | |
| .action-btn { | |
| position: fixed; | |
| width: 70px; | |
| height: 70px; | |
| border-radius: 50%; | |
| border: 2px solid var(--neon-pink); | |
| background: rgba(255, 0, 255, 0.1); | |
| color: var(--neon-pink); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 24px; | |
| z-index: 50; | |
| cursor: pointer; | |
| box-shadow: 0 0 15px rgba(255, 0, 255, 0.3); | |
| } | |
| .action-btn:active { | |
| background: rgba(255, 0, 255, 0.3); | |
| transform: scale(0.95); | |
| } | |
| /* Damage numbers */ | |
| .damage-popup { | |
| position: absolute; | |
| font-family: 'Orbitron', sans-serif; | |
| font-weight: 900; | |
| font-size: 18px; | |
| pointer-events: none; | |
| animation: damage-float 1s ease-out forwards; | |
| z-index: 60; | |
| } | |
| @keyframes damage-float { | |
| 0% { opacity: 1; transform: translateY(0) scale(1); } | |
| 100% { opacity: 0; transform: translateY(-60px) scale(1.3); } | |
| } | |
| /* Level up flash */ | |
| @keyframes level-flash { | |
| 0%, 100% { opacity: 0; } | |
| 50% { opacity: 0.3; } | |
| } | |
| .level-flash { | |
| position: fixed; | |
| inset: 0; | |
| background: var(--neon-cyan); | |
| pointer-events: none; | |
| z-index: 55; | |
| animation: level-flash 0.5s ease-out; | |
| } | |
| /* Grid background for screens */ | |
| .grid-bg { | |
| background-image: | |
| linear-gradient(rgba(0, 240, 255, 0.03) 1px, transparent 1px), | |
| linear-gradient(90deg, rgba(0, 240, 255, 0.03) 1px, transparent 1px); | |
| background-size: 50px 50px; | |
| } | |
| /* Particle effects container */ | |
| .particles-container { | |
| position: fixed; | |
| inset: 0; | |
| pointer-events: none; | |
| z-index: 45; | |
| overflow: hidden; | |
| } | |
| .particle { | |
| position: absolute; | |
| border-radius: 50%; | |
| pointer-events: none; | |
| } | |
| /* Responsive */ | |
| @media (max-width: 768px) { | |
| .joystick-zone { | |
| bottom: 60px; | |
| left: 60px; | |
| width: 110px; | |
| height: 110px; | |
| } | |
| .joystick-base { | |
| width: 90px; | |
| height: 90px; | |
| } | |
| .joystick-stick { | |
| width: 40px; | |
| height: 40px; | |
| } | |
| .action-btn { | |
| width: 55px; | |
| height: 55px; | |
| font-size: 20px; | |
| } | |
| } | |
| /* Scrollbar */ | |
| ::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: #0a0a1a; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: var(--neon-cyan); | |
| border-radius: 3px; | |
| } | |
| /* Title animation */ | |
| @keyframes title-glow { | |
| 0%, 100% { | |
| text-shadow: 0 0 20px var(--neon-cyan), 0 0 40px var(--neon-cyan), 0 0 80px var(--neon-cyan); | |
| } | |
| 50% { | |
| text-shadow: 0 0 30px var(--neon-pink), 0 0 60px var(--neon-pink), 0 0 100px var(--neon-pink); | |
| } | |
| } | |
| .title-glow { | |
| animation: title-glow 3s ease-in-out infinite; | |
| } | |
| /* Combo counter */ | |
| @keyframes combo-pop { | |
| 0% { transform: scale(0.5); opacity: 0; } | |
| 50% { transform: scale(1.3); } | |
| 100% { transform: scale(1); opacity: 1; } | |
| } | |
| .combo-pop { | |
| animation: combo-pop 0.3s ease-out; | |
| } | |
| /* Wave notification */ | |
| @keyframes wave-slide { | |
| 0% { transform: translateX(-100%); opacity: 0; } | |
| 20% { transform: translateX(0); opacity: 1; } | |
| 80% { transform: translateX(0); opacity: 1; } | |
| 100% { transform: translateX(100%); opacity: 0; } | |
| } | |
| .wave-notify { | |
| animation: wave-slide 3s ease-in-out forwards; | |
| } | |
| /* Minimap */ | |
| .minimap { | |
| width: 120px; | |
| height: 120px; | |
| border: 2px solid var(--neon-cyan); | |
| border-radius: 8px; | |
| background: rgba(0, 0, 0, 0.7); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .minimap-dot { | |
| position: absolute; | |
| border-radius: 50%; | |
| } | |
| .minimap-player { | |
| width: 6px; | |
| height: 6px; | |
| background: var(--neon-cyan); | |
| box-shadow: 0 0 6px var(--neon-cyan); | |
| } | |
| .minimap-enemy { | |
| width: 4px; | |
| height: 4px; | |
| background: var(--neon-red); | |
| } | |
| .minimap-orb { | |
| width: 3px; | |
| height: 3px; | |
| background: var(--neon-green); | |
| } | |
| /* Stats display */ | |
| .stat-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| padding: 4px 0; | |
| } | |
| .stat-icon { | |
| width: 24px; | |
| height: 24px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| border-radius: 4px; | |
| font-size: 12px; | |
| } | |
| /* Kill feed */ | |
| .kill-feed { | |
| position: fixed; | |
| top: 80px; | |
| right: 20px; | |
| z-index: 50; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 4px; | |
| align-items: flex-end; | |
| } | |
| .kill-entry { | |
| background: rgba(0, 0, 0, 0.7); | |
| border-right: 3px solid var(--neon-green); | |
| padding: 4px 12px; | |
| border-radius: 4px 0 0 4px; | |
| font-size: 12px; | |
| color: #fff; | |
| animation: kill-slide 2s ease-out forwards; | |
| } | |
| @keyframes kill-slide { | |
| 0% { transform: translateX(50px); opacity: 0; } | |
| 20% { transform: translateX(0); opacity: 1; } | |
| 80% { transform: translateX(0); opacity: 1; } | |
| 100% { transform: translateX(50px); opacity: 0; } | |
| } | |
| /* Floating text */ | |
| .floating-text { | |
| position: absolute; | |
| font-family: 'Orbitron', sans-serif; | |
| font-weight: 700; | |
| pointer-events: none; | |
| z-index: 60; | |
| animation: float-up 1.5s ease-out forwards; | |
| } | |
| @keyframes float-up { | |
| 0% { opacity: 1; transform: translateY(0); } | |
| 100% { opacity: 0; transform: translateY(-80px); } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- CRT Overlay --> | |
| <div class="crt-overlay"></div> | |
| <!-- Particles Container --> | |
| <div class="particles-container" id="particlesContainer"></div> | |
| <!-- Game Canvas --> | |
| <canvas id="gameCanvas"></canvas> | |
| <!-- Kill Feed --> | |
| <div class="kill-feed" id="killFeed"></div> | |
| <!-- START SCREEN --> | |
| <div class="screen grid-bg" id="startScreen"> | |
| <div class="scan-line"></div> | |
| <div class="text-center px-4"> | |
| <div class="mb-2"> | |
| <span class="text-xs tracking-[6px] text-gray-500 uppercase">Built with</span> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="text-xs tracking-[6px] text-cyan-400 hover:text-cyan-300 uppercase transition-colors ml-1">anycoder</a> | |
| </div> | |
| <h1 class="text-5xl md:text-7xl font-black mb-2 title-glow" style="font-family: 'Orbitron', sans-serif;"> | |
| <span class="neon-text-cyan">NEON</span> | |
| <span class="neon-text-pink">SURVIVOR</span> | |
| </h1> | |
| <p class="text-gray-400 text-sm md:text-base tracking-[4px] mb-8 uppercase">Cyberpunk Zombie Survival</p> | |
| <div class="flex flex-col items-center gap-4 mb-8"> | |
| <div class="neon-box rounded-lg p-4 max-w-md w-full"> | |
| <div class="grid grid-cols-2 gap-3 text-xs text-gray-300"> | |
| <div class="flex items-center gap-2"> | |
| <i class="fas fa-keyboard text-cyan-400"></i> | |
| <span>WASD / Arrows to Move</span> | |
| </div> | |
| <div class="flex items-center gap-2"> | |
| <i class="fas fa-mouse text-pink-400"></i> | |
| <span>Auto-aims nearest enemy</span> | |
| </div> | |
| <div class="flex items-center gap-2"> | |
| <i class="fas fa-bolt text-yellow-400"></i> | |
| <span>Collect orbs to level up</span> | |
| </div> | |
| <div class="flex items-center gap-2"> | |
| <i class="fas fa-skull text-red-400"></i> | |
| <span>Survive endless waves</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="flex flex-col sm:flex-row gap-4"> | |
| <button class="neon-btn" id="startBtn"> | |
| <i class="fas fa-play mr-2"></i>Start Game | |
| </button> | |
| <button class="neon-btn neon-btn-pink" id="settingsBtn"> | |
| <i class="fas fa-cog mr-2"></i>Settings | |
| </button> | |
| </div> | |
| <div class="mt-8 text-xs text-gray-600 tracking-wider"> | |
| <p>v2.0.1 | Endless Survival Mode</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- SETTINGS SCREEN --> | |
| <div class="screen grid-bg hidden" id="settingsScreen"> | |
| <div class="text-center px-4 max-w-md w-full"> | |
| <h2 class="text-3xl font-bold neon-text-cyan mb-6" style="font-family: 'Orbitron'">SETTINGS</h2> | |
| <div class="neon-box rounded-lg p-6 mb-6 space-y-4"> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-gray-300 text-sm">Sound Effects</span> | |
| <button class="w-12 h-6 rounded-full bg-cyan-900 relative transition-colors" id="soundToggle"> | |
| <div class="w-5 h-5 rounded-full bg-cyan-400 absolute top-0.5 left-0.5 transition-transform" id="soundKnob"></div> | |
| </button> | |
| </div> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-gray-300 text-sm">Music</span> | |
| <button class="w-12 h-6 rounded-full bg-cyan-900 relative transition-colors" id="musicToggle"> | |
| <div class="w-5 h-5 rounded-full bg-cyan-400 absolute top-0.5 left-0.5 transition-transform" id="musicKnob"></div> | |
| </button> | |
| </div> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-gray-300 text-sm">Screen Shake</span> | |
| <button class="w-12 h-6 rounded-full bg-cyan-900 relative transition-colors" id="shakeToggle"> | |
| <div class="w-5 h-5 rounded-full bg-cyan-400 absolute top-0.5 left-0.5 transition-transform" id="shakeKnob"></div> | |
| </button> | |
| </div> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-gray-300 text-sm">Show Minimap</span> | |
| <button class="w-12 h-6 rounded-full bg-cyan-900 relative transition-colors" id="minimapToggle"> | |
| <div class="w-5 h-5 rounded-full bg-cyan-400 absolute top-0.5 left-0.5 transition-transform" id="minimapKnob"></div> | |
| </button> | |
| </div> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-gray-300 text-sm">Particle Effects</span> | |
| <select class="bg-gray-900 border border-cyan-500/30 rounded px-3 py-1 text-sm text-cyan-400" id="particleSelect"> | |
| <option value="high">High</option> | |
| <option value="medium">Medium</option> | |
| <option value="low">Low</option> | |
| </select> | |
| </div> | |
| </div> | |
| <button class="neon-btn" id="backBtn"> | |
| <i class="fas fa-arrow-left mr-2"></i>Back | |
| </button> | |
| </div> | |
| </div> | |
| <!-- HUD (Heads Up Display) --> | |
| <div id="hud" class="hidden" style="position: fixed; inset: 0; pointer-events: none; z-index: 40;"> | |
| <!-- Top Left: Stats --> | |
| <div class="absolute top-4 left-4 space-y-2"> | |
| <div class="hud-panel"> | |
| <div class="flex items-center gap-3 mb-1"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-cyan-500 to-blue-600 flex items-center justify-center text-white text-xs font-bold" id="levelBadge">1</div> | |
| <div class="flex-1 min-w-[140px]"> | |
| <div class="flex justify-between text-xs mb-0.5"> | |
| <span class="text-cyan-400 font-bold">LVL <span id="levelText">1</span></span> | |
| <span class="text-gray-400" id="xpText">0/100</span> | |
| </div> | |
| <div class="xp-bar"> | |
| <div class="xp-fill" id="xpFill" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="hud-panel"> | |
| <div class="flex items-center gap-2 mb-1"> | |
| <i class="fas fa-heart text-red-500 text-xs"></i> | |
| <div class="flex-1"> | |
| <div class="hp-bar"> | |
| <div class="hp-fill" id="hpFill" style="width: 100%"></div> | |
| </div> | |
| </div> | |
| <span class="text-xs text-red-400 font-bold" id="hpText">100/100</span> | |
| </div> | |
| </div> | |
| <div class="hud-panel flex items-center gap-4 text-xs"> | |
| <div class="flex items-center gap-1"> | |
| <i class="fas fa-clock text-yellow-400"></i> | |
| <span class="text-yellow-400 font-bold" id="timeText">00:00</span> | |
| </div> | |
| <div class="flex items-center gap-1"> | |
| <i class="fas fa-skull text-red-400"></i> | |
| <span class="text-red-400 font-bold" id="killsText">0</span> | |
| </div> | |
| <div class="flex items-center gap-1"> | |
| <i class="fas fa-wave-square text-pink-400"></i> | |
| <span class="text-pink-400 font-bold" id="waveText">Wave 1</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Top Right: Minimap & Combo --> | |
| <div class="absolute top-4 right-4 space-y-2"> | |
| <div class="hud-panel" id="minimapPanel"> | |
| <div class="minimap" id="minimap"> | |
| <div class="minimap-dot minimap-player" id="minimapPlayer"></div> | |
| </div> | |
| </div> | |
| <div class="hud-panel text-center hidden" id="comboPanel"> | |
| <div class="text-2xl font-black neon-text-yellow" id="comboCount" style="font-family: 'Orbitron'">x1</div> | |
| <div class="text-xs text-yellow-400">COMBO</div> | |
| </div> | |
| </div> | |
| <!-- Bottom: Weapons & Skills --> | |
| <div class="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2" id="weaponBar"> | |
| <!-- Weapon slots generated by JS --> | |
| </div> | |
| <!-- Bottom Right: Mobile Controls --> | |
| <div class="joystick-zone md:hidden" id="joystickZone"> | |
| <div class="joystick-base"></div> | |
| <div class="joystick-stick" id="joystickStick"></div> | |
| </div> | |
| <!-- Action buttons for mobile --> | |
| <div class="md:hidden"> | |
| <div class="action-btn" style="bottom: 80px; right: 80px;" id="dashBtn"> | |
| <i class="fas fa-bolt"></i> | |
| </div> | |
| <div class="action-btn" style="bottom: 160px; right: 40px;" id="ultBtn"> | |
| <i class="fas fa-radiation"></i> | |
| </div> | |
| </div> | |
| <!-- Center notifications --> | |
| <div class="absolute top-1/3 left-1/2 -translate-x-1/2 -translate-y-1/2 text-center pointer-events-none" id="centerNotify"></div> | |
| </div> | |
| <!-- LEVEL UP SCREEN --> | |
| <div class="screen hidden" id="levelUpScreen" style="background: rgba(0,0,0,0.85); backdrop-filter: blur(10px);"> | |
| <div class="text-center px-4 max-w-2xl w-full"> | |
| <h2 class="text-4xl font-black neon-text-green mb-2 float" style="font-family: 'Orbitron'">LEVEL UP!</h2> | |
| <p class="text-gray-400 text-sm mb-8 tracking-wider">Choose your upgrade</p> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4" id="skillCards"> | |
| <!-- Generated by JS --> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- PAUSE SCREEN --> | |
| <div class="screen hidden" id="pauseScreen" style="background: rgba(0,0,0,0.8); backdrop-filter: blur(5px);"> | |
| <div class="text-center px-4"> | |
| <h2 class="text-4xl font-bold neon-text-cyan mb-8" style="font-family: 'Orbitron'">PAUSED</h2> | |
| <div class="flex flex-col gap-4"> | |
| <button class="neon-btn" id="resumeBtn"> | |
| <i class="fas fa-play mr-2"></i>Resume | |
| </button> | |
| <button class="neon-btn neon-btn-pink" id="quitBtn"> | |
| <i class="fas fa-door-open mr-2"></i>Quit to Menu | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- GAME OVER SCREEN --> | |
| <div class="screen hidden" id="gameOverScreen" style="background: rgba(0,0,0,0.9);"> | |
| <div class="text-center px-4 max-w-md w-full"> | |
| <h2 class="text-5xl font-black neon-text-red mb-4" style="font-family: 'Orbitron'">ELIMINATED</h2> | |
| <div class="neon-box-pink rounded-lg p-6 mb-6 space-y-3"> | |
| <div class="flex justify-between text-sm"> | |
| <span class="text-gray-400">Survival Time</span> | |
| <span class="neon-text-cyan font-bold" id="finalTime">00:00</span> | |
| </div> | |
| <div class="flex justify-between text-sm"> | |
| <span class="text-gray-400">Enemies Defeated</span> | |
| <span class="neon-text-green font-bold" id="finalKills">0</span> | |
| </div> | |
| <div class="flex justify-between text-sm"> | |
| <span class="text-gray-400">Level Reached</span> | |
| <span class="neon-text-yellow font-bold" id="finalLevel">1</span> | |
| </div> | |
| <div class="flex justify-between text-sm"> | |
| <span class="text-gray-400">Max Combo</span> | |
| <span class="neon-text-pink font-bold" id="finalCombo">x1</span> | |
| </div> | |
| <div class="flex justify-between text-sm"> | |
| <span class="text-gray-400">Waves Survived</span> | |
| <span class="neon-text-cyan font-bold" id="finalWave">1</span> | |
| </div> | |
| <div class="border-t border-gray-700 pt-2 flex justify-between text-base"> | |
| <span class="text-gray-300 font-bold">SCORE</span> | |
| <span class="neon-text-green font-black text-xl" id="finalScore">0</span> | |
| </div> | |
| </div> | |
| <div class="flex flex-col sm:flex-row gap-4"> | |
| <button class="neon-btn" id="restartBtn"> | |
| <i class="fas fa-redo mr-2"></i>Try Again | |
| </button> | |
| <button class="neon-btn neon-btn-pink" id="menuBtn"> | |
| <i class="fas fa-home mr-2"></i>Main Menu | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Wave Notification --> | |
| <div class="fixed top-1/4 left-0 right-0 text-center pointer-events-none z-50 hidden" id="waveNotify"> | |
| <div class="wave-notify inline-block"> | |
| <h3 class="text-3xl md:text-5xl font-black neon-text-pink" style="font-family: 'Orbitron'" id="waveNotifyText">WAVE 1</h3> | |
| <p class="text-gray-400 text-sm mt-1" id="waveNotifySub">The horde approaches...</p> | |
| </div> | |
| </div> | |
| <script> | |
| // ==================== GAME ENGINE ==================== | |
| const canvas = document.getElementById('gameCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| // Game State | |
| const STATE = { | |
| MENU: 0, | |
| PLAYING: 1, | |
| PAUSED: 2, | |
| LEVEL_UP: 3, | |
| GAME_OVER: 4 | |
| }; | |
| let gameState = STATE.MENU; | |
| let lastTime = 0; | |
| let gameTime = 0; | |
| let frameCount = 0; | |
| // Settings | |
| const settings = { | |
| sound: true, | |
| music: false, | |
| shake: true, | |
| minimap: true, | |
| particles: 'high' | |
| }; | |
| // Camera | |
| const camera = { x: 0, y: 0, shakeX: 0, shakeY: 0, shakeIntensity: 0 }; | |
| // World | |
| const WORLD_SIZE = 4000; | |
| const TILE_SIZE = 80; | |
| // Player | |
| const player = { | |
| x: WORLD_SIZE / 2, | |
| y: WORLD_SIZE / 2, | |
| radius: 18, | |
| speed: 200, | |
| hp: 100, | |
| maxHp: 100, | |
| xp: 0, | |
| xpToLevel: 100, | |
| level: 1, | |
| kills: 0, | |
| combo: 0, | |
| maxCombo: 1, | |
| comboTimer: 0, | |
| invincible: 0, | |
| dashCooldown: 0, | |
| ultCharge: 0, | |
| ultMax: 100, | |
| weapons: [], | |
| skills: { | |
| damage: 1, | |
| speed: 1, | |
| hpRegen: 0, | |
| pickupRange: 80, | |
| critChance: 0.05, | |
| critDamage: 1.5, | |
| fireRate: 1, | |
| projectileSpeed: 1, | |
| pierce: 0, | |
| area: 1 | |
| }, | |
| facing: 0 | |
| }; | |
| // Weapons | |
| const WEAPON_TYPES = { | |
| PISTOL: { name: 'Plasma Pistol', icon: 'fa-gun', color: '#00f0ff', damage: 12, fireRate: 400, projectileSpeed: 400, pierce: 0, auto: true }, | |
| SHOTGUN: { name: 'Scatter Cannon', icon: 'fa-bullseye', color: '#ff00ff', damage: 8, fireRate: 800, projectileSpeed: 350, pierce: 1, count: 5, spread: 0.3, auto: false }, | |
| RIFLE: { name: 'Pulse Rifle', icon: 'fa-crosshairs', color: '#39ff14', damage: 6, fireRate: 150, projectileSpeed: 500, pierce: 1, auto: true }, | |
| LASER: { name: 'Beam Cutter', icon: 'fa-bolt', color: '#ffff00', damage: 3, fireRate: 50, projectileSpeed: 800, pierce: 3, auto: true }, | |
| ROCKET: { name: 'RPG-7', icon: 'fa-rocket', color: '#ff073a', damage: 40, fireRate: 1500, projectileSpeed: 250, pierce: 0, explosion: 80, auto: false }, | |
| ORBITAL: { name: 'Orbital Drones', icon: 'fa-satellite', color: '#00f0ff', damage: 15, fireRate: 0, orbital: true, orbitRadius: 60, orbitSpeed: 3, auto: true } | |
| }; | |
| // Enemies | |
| const ENEMY_TYPES = { | |
| WALKER: { name: 'Walker', hp: 30, damage: 10, speed: 80, radius: 16, color: '#ff4444', xp: 10, score: 10 }, | |
| RUNNER: { name: 'Runner', hp: 20, damage: 15, speed: 160, radius: 14, color: '#ff8800', xp: 15, score: 20 }, | |
| TANK: { name: 'Tank', hp: 120, damage: 25, speed: 50, radius: 28, color: '#8800ff', xp: 40, score: 50 }, | |
| SPITTER: { name: 'Spitter', hp: 40, damage: 12, speed: 60, radius: 16, color: '#00ff44', xp: 20, score: 30, ranged: true, projectileSpeed: 200 }, | |
| BOSS: { name: 'Overlord', hp: 500, damage: 40, speed: 40, radius: 45, color: '#ff0088', xp: 200, score: 200, boss: true } | |
| }; | |
| // Arrays | |
| let enemies = []; | |
| let projectiles = []; | |
| let particles = []; | |
| let orbs = []; | |
| let enemyProjectiles = []; | |
| let damageNumbers = []; | |
| let floatingTexts = []; | |
| // Wave System | |
| let wave = 1; | |
| let waveTimer = 0; | |
| let waveDuration = 60; | |
| let spawnTimer = 0; | |
| let bossSpawned = false; | |
| // Input | |
| const keys = {}; | |
| const mouse = { x: 0, y: 0, worldX: 0, worldY: 0, down: false }; | |
| const joystick = { active: false, dx: 0, dy: 0, startX: 0, startY: 0 }; | |
| // Resize | |
| function resize() { | |
| canvas.width = window.innerWidth; | |
| canvas.height = window.innerHeight; | |
| } | |
| window.addEventListener('resize', resize); | |
| resize(); | |
| // ==================== INPUT HANDLING ==================== | |
| document.addEventListener('keydown', e => { | |
| keys[e.code] = true; | |
| if (e.code === 'Escape' && gameState === STATE.PLAYING) { | |
| pauseGame(); | |
| } | |
| if (e.code === 'KeyP' && gameState === STATE.PLAYING) { | |
| pauseGame(); | |
| } | |
| }); | |
| document.addEventListener('keyup', e => keys[e.code] = false); | |
| canvas.addEventListener('mousemove', e => { | |
| mouse.x = e.clientX; | |
| mouse.y = e.clientY; | |
| mouse.worldX = e.clientX + camera.x; | |
| mouse.worldY = e.clientY + camera.y; | |
| }); | |
| canvas.addEventListener('mousedown', () => mouse.down = true); | |
| canvas.addEventListener('mouseup', () => mouse.down = false); | |
| // Touch / Joystick | |
| const joystickZone = document.getElementById('joystickZone'); | |
| const joystickStick = document.getElementById('joystickStick'); | |
| joystickZone.addEventListener('touchstart', e => { | |
| e.preventDefault(); | |
| const touch = e.touches[0]; | |
| const rect = joystickZone.getBoundingClientRect(); | |
| joystick.active = true; | |
| joystick.startX = rect.left + rect.width / 2; | |
| joystick.startY = rect.top + rect.height / 2; | |
| updateJoystick(touch.clientX, touch.clientY); | |
| }, { passive: false }); | |
| joystickZone.addEventListener('touchmove', e => { | |
| e.preventDefault(); | |
| if (joystick.active) { | |
| updateJoystick(e.touches[0].clientX, e.touches[0].clientY); | |
| } | |
| }, { passive: false }); | |
| joystickZone.addEventListener('touchend', e => { | |
| e.preventDefault(); | |
| joystick.active = false; | |
| joystick.dx = 0; | |
| joystick.dy = 0; | |
| joystickStick.style.transform = 'translate(-50%, -50%)'; | |
| }); | |
| function updateJoystick(x, y) { | |
| const maxDist = 45; | |
| let dx = x - joystick.startX; | |
| let dy = y - joystick.startY; | |
| const dist = Math.sqrt(dx * dx + dy * dy); | |
| if (dist > maxDist) { | |
| dx = (dx / dist) * maxDist; | |
| dy = (dy / dist) * maxDist; | |
| } | |
| joystick.dx = dx / maxDist; | |
| joystick.dy = dy / maxDist; | |
| joystickStick.style.transform = `translate(calc(-50% + ${dx}px), calc(-50% + ${dy}px))`; | |
| } | |
| // Mobile action buttons | |
| document.getElementById('dashBtn').addEventListener('touchstart', e => { | |
| e.preventDefault(); | |
| dash(); | |
| }); | |
| document.getElementById('ultBtn').addEventListener('touchstart', e => { | |
| e.preventDefault(); | |
| useUltimate(); | |
| }); | |
| // ==================== SCREEN MANAGEMENT ==================== | |
| function showScreen(id) { | |
| document.querySelectorAll('.screen').forEach(s => s.classList.add('hidden')); | |
| document.getElementById(id).classList.remove('hidden'); | |
| } | |
| function hideAllScreens() { | |
| document.querySelectorAll('.screen').forEach(s => s.classList.add('hidden')); | |
| } | |
| // Start Screen | |
| document.getElementById('startBtn').addEventListener('click', startGame); | |
| document.getElementById('settingsBtn').addEventListener('click', () => showScreen('settingsScreen')); | |
| document.getElementById('backBtn').addEventListener('click', () => showScreen('startScreen')); | |
| // Settings toggles | |
| function setupToggle(id, knobId, settingKey) { | |
| const btn = document.getElementById(id); | |
| const knob = document.getElementById(knobId); | |
| btn.addEventListener('click', () => { | |
| settings[settingKey] = !settings[settingKey]; | |
| btn.style.background = settings[settingKey] ? '#004444' : '#222'; | |
| knob.style.transform = settings[settingKey] ? 'translateX(24px)' : 'translateX(0)'; | |
| knob.style.background = settings[settingKey] ? 'var(--neon-cyan)' : '#666'; | |
| }); | |
| // Init | |
| btn.style.background = settings[settingKey] ? '#004444' : '#222'; | |
| knob.style.transform = settings[settingKey] ? 'translateX(24px)' : 'translateX(0)'; | |
| knob.style.background = settings[settingKey] ? 'var(--neon-cyan)' : '#666'; | |
| } | |
| setupToggle('soundToggle', 'soundKnob', 'sound'); | |
| setupToggle('musicToggle', 'musicKnob', 'music'); | |
| setupToggle('shakeToggle', 'shakeKnob', 'shake'); | |
| setupToggle('minimapToggle', 'minimapKnob', 'minimap'); | |
| document.getElementById('particleSelect').addEventListener('change', e => { | |
| settings.particles = e.target.value; | |
| }); | |
| // Pause | |
| document.getElementById('resumeBtn').addEventListener('click', resumeGame); | |
| document.getElementById('quitBtn').addEventListener('click', () => { | |
| gameState = STATE.M |