NEON SURVIVORS v1.1 — full-featured bullet-heaven survivor game
Vanilla JS + Canvas, zero dependencies, offline-first PWA. Gameplay: - 11 weapons x8 levels + 11 evolutions (chest-based), incl. timed mines - 13 passives, crit system with directional hit-sparks & hit-stop - 10 characters w/ unique mods + unlock conditions, gold cosmetic skins - 3 biomes (Neon Graveyard / Frozen Hollow / Magma Rift) each with own spawn tables, boss plans and music flavor; Endless mode + surges; 4 difficulty grades; breakable crystal-lamp props - Elite random affixes (Swift/Sturdy/Volatile), 4 bosses, win flow - Achievements (23) w/ gold rewards, run history, daily seeded challenge Tech: - Cinematic canvas main-menu scene, game-feel FX suite (trails, muzzle, status tints, low-HP pulse), viewport culling + particle pooling - WebAudio synth SFX + generative per-biome soundtrack - Gamepad support, remappable keys, touch joystick, fullscreen - i18n VI/EN, localStorage saves w/ export-import codes - Cloudflare Workers leaderboard scaffold (KV) w/ signed submits - Headless integrity test-suite (node test/integrity.js)
This commit is contained in:
+226
@@ -0,0 +1,226 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="vi">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="theme-color" content="#7c5cff">
|
||||
<link rel="manifest" href="manifest.webmanifest">
|
||||
<link rel="apple-touch-icon" href="icons/icon-192.png">
|
||||
<title>NEON SURVIVORS — Bullet Heaven</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🎮</text></svg>">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="game"></canvas>
|
||||
|
||||
<!-- FPS counter -->
|
||||
<div id="fpsMeter" class="hidden">60</div>
|
||||
|
||||
<!-- Touch joystick -->
|
||||
<div id="touchLayer" class="hidden">
|
||||
<div id="stickBase"><div id="stickKnob"></div></div>
|
||||
</div>
|
||||
|
||||
<!-- ===== UI OVERLAY ===== -->
|
||||
<div id="ui">
|
||||
|
||||
<!-- Loading splash -->
|
||||
<div class="screen" id="scr-loading">
|
||||
<div class="logo-pop">NEON<span>SURVIVORS</span></div>
|
||||
<div class="loading-bar"><i></i></div>
|
||||
</div>
|
||||
|
||||
<!-- Main menu -->
|
||||
<div class="screen hidden" id="scr-menu">
|
||||
<div class="menu-wrap">
|
||||
<header class="menu-head">
|
||||
<h1 class="logo"><span class="l1">NEON</span><span class="l2">SURVIVORS</span></h1>
|
||||
<p class="tagline" data-i18n="tagline"></p>
|
||||
<div class="ver-chip">BULLET HEAVEN · v1.1</div>
|
||||
</header>
|
||||
|
||||
<nav class="menu-btns">
|
||||
<button class="mbtn primary" id="bt-play"><i>▶</i><span data-i18n="btn_play"></span></button>
|
||||
<button class="mbtn" id="bt-daily"><i>⚡</i><span data-i18n="btn_daily"></span></button>
|
||||
<button class="mbtn" id="bt-shop"><i>🛒</i><span data-i18n="ms_title"></span></button>
|
||||
<button class="mbtn" id="bt-codex"><i>📖</i><span data-i18n="btn_codex"></span></button>
|
||||
<button class="mbtn" id="bt-history"><i>📜</i><span data-i18n="btn_history"></span></button>
|
||||
<button class="mbtn" id="bt-board"><i>🥇</i><span data-i18n="btn_board"></span></button>
|
||||
<button class="mbtn" id="bt-options"><i>⚙️</i><span data-i18n="btn_options"></span></button>
|
||||
</nav>
|
||||
|
||||
<footer class="menu-foot">
|
||||
<div class="menu-stats">
|
||||
<span class="chip">🪙 <b id="menuGold">0</b></span>
|
||||
<span class="chip">💀 <b id="menuKills">0</b></span>
|
||||
<span class="chip">🏆 <b id="menuBest">00:00</b></span>
|
||||
</div>
|
||||
<p class="hint" data-i18n="tip_move"></p>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Character select -->
|
||||
<div class="screen hidden" id="scr-chars">
|
||||
<header class="scr-head"><button class="btn btn-icon back-btn">◀</button><h2 data-i18n="scr_chars"></h2><span class="head-gold">🪙 <b>0</b></span></header>
|
||||
<div class="card-grid" id="charGrid"></div>
|
||||
</div>
|
||||
|
||||
<!-- Stage select -->
|
||||
<div class="screen hidden" id="scr-stage">
|
||||
<header class="scr-head"><button class="btn btn-icon back-btn">◀</button><h2 data-i18n="st_select"></h2><span class="head-gold">🪙 <b>0</b></span></header>
|
||||
<div class="stage-grid" id="stageGrid"></div>
|
||||
<div class="stage-opts" id="stageOpts"></div>
|
||||
<div class="start-bar" style="position:absolute;bottom:1rem;left:0;right:0;display:flex;justify-content:center;z-index:5">
|
||||
<button class="btn btn-primary btn-big" id="bt-stage-go">▶</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Run history -->
|
||||
<div class="screen hidden" id="scr-history">
|
||||
<header class="scr-head"><button class="btn btn-icon back-btn">◀</button><h2 data-i18n="btn_history"></h2><span></span></header>
|
||||
<div class="hist-summary" id="histSummary"></div>
|
||||
<div class="hist-list" id="histList"></div>
|
||||
</div>
|
||||
|
||||
<!-- Meta shop -->
|
||||
<div class="screen hidden" id="scr-shop">
|
||||
<header class="scr-head"><button class="btn btn-icon back-btn">◀</button><h2 data-i18n="ms_title"></h2><span class="head-gold">🪙 <b>0</b></span></header>
|
||||
<div class="shop-grid" id="shopGrid"></div>
|
||||
</div>
|
||||
|
||||
<!-- Codex -->
|
||||
<div class="screen hidden" id="scr-codex">
|
||||
<header class="scr-head"><button class="btn btn-icon back-btn">◀</button><h2 data-i18n="btn_codex"></h2><span></span></header>
|
||||
<nav class="tabs" id="codexTabs">
|
||||
<button class="tab active" data-tab="weapons" data-i18n="cx_weapons"></button>
|
||||
<button class="tab" data-tab="passives" data-i18n="cx_passives"></button>
|
||||
<button class="tab" data-tab="enemies" data-i18n="cx_enemies"></button>
|
||||
<button class="tab" data-tab="chars" data-i18n="cx_chars"></button>
|
||||
<button class="tab" data-tab="ach">🏆 <span data-i18n="cx_ach"></span></button>
|
||||
</nav>
|
||||
<div class="codex-list" id="codexList"></div>
|
||||
</div>
|
||||
|
||||
<!-- Options -->
|
||||
<div class="screen hidden" id="scr-options">
|
||||
<header class="scr-head"><button class="btn btn-icon back-btn">◀</button><h2 data-i18n="btn_options"></h2><span></span></header>
|
||||
<div class="opt-panel" id="optPanel"></div>
|
||||
</div>
|
||||
|
||||
<!-- HUD -->
|
||||
<div class="hidden" id="hud">
|
||||
<div id="xpBar"><i id="xpFill"></i><span id="lvlTag">LV 1</span></div>
|
||||
<div id="hudTop">
|
||||
<div id="hudPortrait"><span id="portraitSym">🧙</span><em id="hudLevel">1</em></div>
|
||||
<div id="hudTimer">00:00</div>
|
||||
<div id="hudRight"><span id="hudGold">🪙 0</span><span id="hudKills">💀 0</span></div>
|
||||
</div>
|
||||
<div id="bossBar" class="hidden"><label id="bossName"></label><div class="bb-track"><i id="bossFill"></i></div></div>
|
||||
<div id="slotWeapons"></div>
|
||||
<div id="slotPassives"></div>
|
||||
</div>
|
||||
|
||||
<!-- Pause -->
|
||||
<div class="modal hidden" id="md-pause">
|
||||
<div class="panel">
|
||||
<h2 data-i18n="scr_pause"></h2>
|
||||
<div id="pauseStats" class="pause-stats"></div>
|
||||
<div class="col-btns">
|
||||
<button class="btn btn-primary" id="bt-resume" data-i18n="btn_resume"></button>
|
||||
<button class="btn" id="bt-poptions" data-i18n="btn_options"></button>
|
||||
<button class="btn btn-danger" id="bt-quit" data-i18n="btn_quitmenu"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Level up -->
|
||||
<div class="modal hidden" id="md-level">
|
||||
<div class="panel panel-up">
|
||||
<h2 data-i18n="lv_title"></h2>
|
||||
<p class="sub" data-i18n="lv_choose"></p>
|
||||
<div id="levelChoices" class="choice-list"></div>
|
||||
<div class="row-btns">
|
||||
<button class="btn btn-small" id="bt-reroll"></button>
|
||||
<button class="btn btn-small" id="bt-skipLv"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Chest -->
|
||||
<div class="modal hidden" id="md-chest">
|
||||
<div class="panel panel-chest">
|
||||
<div class="chest-art" id="chestArt">🎁</div>
|
||||
<h2 id="chestTitle"></h2>
|
||||
<div id="chestBody"></div>
|
||||
<button class="btn btn-primary" id="bt-chestOk" data-i18n="btn_continue"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Game over / victory -->
|
||||
<div class="modal hidden" id="md-over">
|
||||
<div class="panel panel-over">
|
||||
<h2 id="overTitle"></h2>
|
||||
<p id="overRecord" class="record hidden" data-i18n="es_newrec"></p>
|
||||
<div class="over-grid" id="overStats"></div>
|
||||
<div class="col-btns">
|
||||
<button class="btn btn-primary" id="bt-retry" data-i18n="btn_restart"></button>
|
||||
<button class="btn" id="bt-tomenu" data-i18n="btn_quitmenu"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Developer tools -->
|
||||
<button id="devBtn" class="hidden" title="Developer Tools (`)">🔧</button>
|
||||
<div class="modal hidden" id="md-dev">
|
||||
<div class="panel panel-dev" id="devPanel"></div>
|
||||
</div>
|
||||
|
||||
<!-- Save export / import -->
|
||||
<div class="modal hidden" id="md-save">
|
||||
<div class="panel panel-save">
|
||||
<h3 data-i18n="save_title"></h3>
|
||||
<textarea id="saveArea" rows="7" spellcheck="false"></textarea>
|
||||
<div class="save-btns">
|
||||
<button class="btn btn-small" id="bt-save-copy" data-i18n="save_copy"></button>
|
||||
<button class="btn btn-small" id="bt-save-import" data-i18n="save_import"></button>
|
||||
<button class="btn btn-small" id="bt-save-close" data-i18n="btn_close"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Leaderboard -->
|
||||
<div class="modal hidden" id="md-lb">
|
||||
<div class="panel panel-lb">
|
||||
<h3 data-i18n="lb_title"></h3>
|
||||
<div class="seg lb-scopes" id="lbScopes"></div>
|
||||
<div class="lb-list" id="lbList"></div>
|
||||
<div class="save-btns"><button class="btn btn-small" id="bt-lb-close" data-i18n="btn_close"></button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tutorial bubble -->
|
||||
<div id="tutTip" class="hidden">
|
||||
<span id="tutText"></span>
|
||||
<button id="bt-tut-skip">✕</button>
|
||||
</div>
|
||||
|
||||
<!-- Toasts -->
|
||||
<div id="toasts"></div>
|
||||
</div>
|
||||
|
||||
<script src="js/util.js"></script>
|
||||
<script src="js/i18n.js"></script>
|
||||
<script src="js/save.js"></script>
|
||||
<script src="js/audio.js"></script>
|
||||
<script src="js/data.js"></script>
|
||||
<script src="js/achievements.js"></script>
|
||||
<script src="js/entities.js"></script>
|
||||
<script src="js/systems.js"></script>
|
||||
<script src="js/render.js"></script>
|
||||
<script src="js/ui.js"></script>
|
||||
<script src="js/game.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user