Files
Wackelpeter/web/index.html
T

319 lines
13 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Wackelpeter</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #000; }
canvas {
display: block;
cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill='none' stroke='%23140d02' stroke-width='4.5' stroke-linecap='round'%3E%3Ccircle cx='20' cy='20' r='13'/%3E%3Cpath d='M20 2v5M20 33v5M2 20h5M33 20h5'/%3E%3C/g%3E%3Cg fill='none' stroke='%23ffc83d' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='20' cy='20' r='13'/%3E%3Cpath d='M20 2v5M20 33v5M2 20h5M33 20h5'/%3E%3C/g%3E%3Cg fill='%23ffc83d' stroke='%23140d02' stroke-width='1'%3E%3Cpath d='M20 0l1.6 3.4L18.4 3.4Z'/%3E%3Cpath d='M20 40l1.6-3.4L18.4 36.6Z'/%3E%3Cpath d='M0 20l3.4-1.6L3.4 21.6Z'/%3E%3Cpath d='M40 20l-3.4-1.6L36.6 21.6Z'/%3E%3C/g%3E%3Cg fill='%23ffc83d' stroke='%23140d02' stroke-width='1'%3E%3Crect x='8.2' y='8.2' width='3.6' height='3.6' transform='rotate(45 10 10)'/%3E%3Crect x='28.2' y='8.2' width='3.6' height='3.6' transform='rotate(45 30 10)'/%3E%3Crect x='8.2' y='28.2' width='3.6' height='3.6' transform='rotate(45 10 30)'/%3E%3Crect x='28.2' y='28.2' width='3.6' height='3.6' transform='rotate(45 30 30)'/%3E%3C/g%3E%3Ccircle cx='20' cy='20' r='2.6' fill='%23ffe9a8' stroke='%23140d02' stroke-width='1'/%3E%3C/svg%3E") 20 20, crosshair;
}
#ui-overlay {
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
pointer-events: none; font-family: monospace; z-index: 10;
}
#damage-vignette {
position: absolute; inset: 0; opacity: 0; pointer-events: none;
background: radial-gradient(ellipse at center,
rgba(255,0,0,0) 40%, rgba(255,0,0,0.35) 100%);
box-shadow: inset 0 0 120px 40px rgba(255,0,0,0.5);
}
#damage-vignette.hurt { animation: hurt-flash 0.45s ease-out; }
@keyframes hurt-flash {
0% { opacity: 1; }
100% { opacity: 0; }
}
#low-hp-vignette {
position: absolute; inset: 0; opacity: 0; pointer-events: none;
background: radial-gradient(ellipse at center,
rgba(255,0,0,0.05) 0%, rgba(255,0,0,0.15) 55%, rgba(220,0,0,0.7) 100%);
box-shadow: inset 0 0 160px 60px rgba(220,0,0,0.55);
}
#low-hp-vignette.active { animation: low-hp-pulse 1.1s ease-in-out infinite; }
@keyframes low-hp-pulse {
0%, 100% { opacity: 0.25; }
50% { opacity: 0.6; }
}
#health-bar-bg {
position: absolute; top: 16px; left: 16px; width: 250px; height: 20px;
background: rgba(0,0,0,0.6); border: 2px solid #555;
}
#health-bar {
position: absolute; top: 16px; left: 16px; width: 250px; height: 20px;
background: #cc0000;
transition: width 0.1s linear;
}
#health-text {
position: absolute; top: 16px; left: 16px; width: 250px; height: 20px;
text-align: center; line-height: 20px; color: #fff; font-size: 12px;
}
#wave-label {
position: absolute; top: 48px; left: 16px; color: #ffcc00; font-size: 18px;
font-family: monospace; text-shadow: 2px 2px 4px #000;
}
#kills-label {
position: absolute; top: 72px; left: 16px; color: #ffcc00; font-size: 16px;
font-family: monospace; text-shadow: 2px 2px 4px #000;
}
.cooldown-container {
position: absolute; left: 16px; width: 200px; height: 16px;
}
.cooldown-bg {
width: 100%; height: 100%; background: rgba(0,0,0,0.6); border: 1px solid #555;
}
.cooldown-fill {
height: 100%; background: #2266dd; transition: width 0.05s linear;
}
.cooldown-label {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
text-align: left; line-height: 16px; color: #fff; font-size: 11px;
padding-left: 4px; font-family: monospace;
}
#fireball-cooldown { bottom: 72px; }
#sword-cooldown { bottom: 48px; }
#teleport-cooldown { bottom: 24px; }
#lightning-cooldown { bottom: 96px; }
#wave-bar-container {
position: absolute; top: 16px; right: 16px; width: 250px; height: 16px;
}
#wave-bar-bg {
width: 100%; height: 100%; background: rgba(0,0,0,0.6); border: 1px solid #555;
}
#wave-bar-fill {
height: 100%; background: #ccaa00; transition: width 0.1s linear;
}
#wave-bar-label {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
text-align: center; line-height: 16px; color: #fff; font-size: 11px;
font-family: monospace;
}
#game-over {
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
font-size: 100px; color: #fff; font-family: monospace; opacity: 0;
text-shadow: 4px 4px 8px #000;
transition: opacity 2s ease-in;
}
#game-over-panel {
position: absolute; top: 62%; left: 50%; transform: translate(-50%, -50%);
display: flex; flex-direction: column; align-items: center; gap: 12px;
pointer-events: none; opacity: 0; transition: opacity 0.8s ease-in 1.5s;
font-family: monospace;
}
#game-over-stats {
color: #ffcc00; font-size: 20px; text-shadow: 2px 2px 4px #000;
}
.menu-button {
pointer-events: auto; cursor: pointer;
background: rgba(0,0,0,0.7); color: #fff; font-family: monospace;
font-size: 18px; padding: 10px 28px; border: 2px solid #888;
}
.menu-button:hover { background: #333; border-color: #ffcc00; color: #ffcc00; }
#main-menu {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
display: flex; flex-direction: column; align-items: center; justify-content: center;
gap: 18px; pointer-events: auto; background: rgba(0,0,0,0.55);
transition: opacity 0.6s ease; font-family: monospace;
}
#main-menu h1 {
color: #fff; font-size: 72px; text-shadow: 4px 4px 8px #000;
}
#main-menu .subtitle {
color: #ffcc00; font-size: 20px; text-shadow: 2px 2px 4px #000;
}
#main-menu .menu-controls {
color: rgba(255,255,255,0.8); font-size: 13px; text-align: center;
line-height: 1.7;
}
#btn-start { font-size: 24px; padding: 14px 48px; }
#btn-confirm { font-size: 18px; padding: 10px 36px; }
#btn-confirm:disabled { opacity: 0.35; cursor: default; }
#instructions {
position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%);
color: rgba(255,255,255,0.5); font-size: 11px; font-family: monospace;
text-align: center;
}
#seed-input {
background: rgba(0,0,0,0.7); border: 2px solid #555; color: #ffcc00;
font-family: monospace; font-size: 16px; padding: 6px 10px; width: 180px;
text-align: center; outline: none;
}
#seed-input:focus { border-color: #ffcc00; }
#level-label {
position: absolute; top: 96px; left: 16px; color: #88ff88; font-size: 16px;
font-family: monospace; text-shadow: 2px 2px 4px #000;
}
#seed-label {
position: absolute; top: 96px; right: 16px; color: rgba(255,255,255,0.6);
font-size: 12px; font-family: monospace; text-shadow: 1px 1px 2px #000;
}
#xp-bar-container {
position: absolute; top: 120px; left: 16px; width: 250px; height: 12px;
}
#xp-bar-bg {
width: 100%; height: 100%; background: rgba(0,0,0,0.6); border: 1px solid #555;
}
#xp-bar-fill {
height: 100%; background: #44cc44; transition: width 0.1s linear;
}
#xp-bar-label {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
text-align: center; line-height: 12px; color: #fff; font-size: 10px;
font-family: monospace;
}
#shield-bar-bg {
position: absolute; top: 44px; left: 16px; width: 250px; height: 10px;
background: rgba(0,0,0,0.6); border: 1px solid #555; display: none;
}
#shield-bar {
position: absolute; top: 44px; left: 16px; width: 250px; height: 10px;
background: #3399ff; transition: width 0.1s linear; display: none;
}
#shield-text {
position: absolute; top: 44px; left: 16px; width: 250px; height: 10px;
text-align: center; line-height: 10px; color: #fff; font-size: 9px;
font-family: monospace; display: none;
}
#level-up {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
display: flex; flex-direction: column; align-items: center; justify-content: center;
gap: 24px; background: rgba(0,0,0,0.7); opacity: 0; pointer-events: none;
transition: opacity 0.3s ease; font-family: monospace;
}
#level-up h2 {
color: #ffcc00; font-size: 44px; text-shadow: 3px 3px 6px #000;
}
#offer-row {
display: flex; gap: 20px;
}
.offer-card {
width: 230px; min-height: 220px; background: rgba(20,20,30,0.9);
border: 2px solid #888; padding: 14px; cursor: pointer;
display: flex; flex-direction: column; gap: 10px;
transition: transform 0.1s ease, border-color 0.1s ease;
}
.offer-card:hover { border-color: #ffcc00; background: rgba(40,40,50,0.95); }
.offer-card.selected {
border-color: #ffcc00; background: rgba(60,50,20,0.95);
transform: scale(1.04); box-shadow: 0 0 18px rgba(255,204,0,0.4);
}
.offer-icon {
width: 76px; height: 76px; margin: 2px auto 0;
filter: drop-shadow(0 3px 6px rgba(0,0,0,0.55));
transition: filter 0.1s ease;
}
.offer-icon svg { width: 100%; height: 100%; display: block; }
.offer-card:hover .offer-icon, .offer-card.selected .offer-icon {
filter: drop-shadow(0 0 9px rgba(255,204,0,0.5));
}
.offer-title {
color: #ffcc00; font-size: 18px; font-weight: bold; text-align: center;
}
.offer-desc {
color: rgba(255,255,255,0.85); font-size: 13px; line-height: 1.5;
}
.offer-hint {
color: rgba(255,255,255,0.4); font-size: 12px; margin-top: auto;
}
</style>
</head>
<body>
<div id="ui-overlay">
<div id="damage-vignette"></div>
<div id="low-hp-vignette"></div>
<div id="health-bar-bg"></div>
<div id="health-bar"></div>
<div id="health-text">100</div>
<div id="shield-bar-bg"></div>
<div id="shield-bar"></div>
<div id="shield-text"></div>
<div id="wave-label">Wave 0</div>
<div id="kills-label">Kills: 0</div>
<div id="level-label">Level 0</div>
<div id="xp-bar-container">
<div id="xp-bar-bg"></div>
<div id="xp-bar-fill"></div>
<div id="xp-bar-label">XP: 0/20</div>
</div>
<div id="seed-label"></div>
<div id="fireball-cooldown" class="cooldown-container" style="display: none">
<div class="cooldown-bg"></div>
<div class="cooldown-fill"></div>
<div class="cooldown-label">Fireball</div>
</div>
<div id="sword-cooldown" class="cooldown-container">
<div class="cooldown-bg"></div>
<div class="cooldown-fill"></div>
<div class="cooldown-label">Sword</div>
</div>
<div id="teleport-cooldown" class="cooldown-container" style="display: none">
<div class="cooldown-bg"></div>
<div class="cooldown-fill"></div>
<div class="cooldown-label">Teleport</div>
</div>
<div id="lightning-cooldown" class="cooldown-container" style="display: none">
<div class="cooldown-bg"></div>
<div class="cooldown-fill"></div>
<div class="cooldown-label">Chain Lightning</div>
</div>
<div id="wave-bar-container">
<div id="wave-bar-bg"></div>
<div id="wave-bar-fill"></div>
<div id="wave-bar-label">Next Wave...</div>
</div>
<div id="game-over">Verloren!</div>
<div id="game-over-panel">
<div id="game-over-stats"></div>
<button id="btn-restart" class="menu-button">Nochmal spielen</button>
<button id="btn-menu" class="menu-button">Hauptmenü</button>
</div>
<div id="level-up">
<h2>Level Up!</h2>
<div id="offer-row">
<div id="offer-0" class="offer-card">
<div id="offer-icon-0" class="offer-icon"></div>
<div id="offer-title-0" class="offer-title"></div>
<div id="offer-desc-0" class="offer-desc"></div>
<div class="offer-hint">[1] auswählen</div>
</div>
<div id="offer-1" class="offer-card">
<div id="offer-icon-1" class="offer-icon"></div>
<div id="offer-title-1" class="offer-title"></div>
<div id="offer-desc-1" class="offer-desc"></div>
<div class="offer-hint">[2] auswählen</div>
</div>
<div id="offer-2" class="offer-card">
<div id="offer-icon-2" class="offer-icon"></div>
<div id="offer-title-2" class="offer-title"></div>
<div id="offer-desc-2" class="offer-desc"></div>
<div class="offer-hint">[3] auswählen</div>
</div>
</div>
<button id="btn-confirm" class="menu-button" disabled>Bestätigen (Enter)</button>
</div>
<div id="main-menu">
<h1>WACKELPETER</h1>
<div class="subtitle">Ein Blob kämpft ums Überleben</div>
<div class="menu-controls">
WASD: Bewegen · Space: Springen · Maus: Zielen<br>
Linksklick: Schwert · Rechtsklick: Feuerball (per Skill) · Q: Kettenblitz (per Skill) · E: Teleport (per Skill)
</div>
<input id="seed-input" type="text" placeholder="Seed (leer = zufällig)" />
<button id="btn-start" class="menu-button">Start</button>
</div>
<div id="instructions">
WASD: Move · Space: Jump · Mouse: Aim · Left Click: Sword · Right Click: Fireball · Q: Lightning · E: Teleport
</div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>