Aethelgard
inkling · composer

Reviews & generation details
Reviews
No human review yet. Unreviewed does not mean unsuccessful.
Generation context
Imported historical artifact. Its exact original instructions and lineage are not known.
Generation prompt · exact text unavailable
See the current prompt for reference. It may differ from the instructions used to generate this artifact.
Inspect original source 34,498 bytes · SHA-256 c6b2dc6d5010
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Aethelgard — Resonant Chronicles</title>
<script src="https://cdn.tailwindcss.com/"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;800&family=Orbitron:wght@700;900&display=swap">
<style>
/* ── css: theme ── */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;800&family=Orbitron:wght@700;900&display=swap');
:root {
--bg-deep: #0a0912;
--bg-card: rgba(255, 255, 255, 0.04);
--glass-border: rgba(255, 255, 255, 0.08);
--text-primary: #f0ecf5;
--text-dim: #a09aa8;
--accent-violet: #7c3aed;
--accent-cyan: #22d3ee;
--accent-amber: #f59e0b;
--pyro: #ff502f;
--hydro: #3b82f6;
--flora: #22c55e;
--zephyr: #a855f7;
--earth: #8b6914;
--volt: #facc15;
--cosmos: #c0c0ff;
}
* { box-sizing: border-box; }
body {
margin: 0; padding: 0;
background: linear-gradient(135deg, #0a0912 0%, #140b1e 50%, #0f1220 100%);
color: var(--text-primary);
font-family: 'Inter', sans-serif;
min-height: 100vh;
overflow-x: hidden;
background-attachment: fixed;
}
.glass {
background: var(--bg-card);
backdrop-filter: blur(20px) saturate(180%);
-webkit-backdrop-filter: blur(20px) saturate(180%);
border: 1px solid var(--glass-border);
border-radius: 1.25rem;
box-shadow: 0 8px 32px rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.05);
}
.glass-card {
background: linear-gradient(145deg, rgba(255,255,255,0.03) 0%, rgba(255,255,255,0.01) 100%);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 1rem;
backdrop-filter: blur(16px);
box-shadow: 0 8px 32px rgba(0,0,0,0.25);
}
.neon-border-pyro { box-shadow: 0 0 12px rgba(255,80,47,0.4), 0 0 24px rgba(255,80,47,0.15); border-color: rgba(255,80,47,0.35); }
.neon-border-hydro { box-shadow: 0 0 12px rgba(59,130,246,0.4), 0 0 24px rgba(59,130,246,0.15); border-color: rgba(59,130,246,0.35); }
.neon-border-flora { box-shadow: 0 0 12px rgba(34,197,94,0.4), 0 0 24px rgba(34,197,94,0.15); border-color: rgba(34,197,94,0.35); }
.neon-border-zephyr { box-shadow: 0 0 12px rgba(168,85,247,0.4), 0 0 24px rgba(168,85,247,0.15); border-color: rgba(168,85,247,0.35); }
.neon-border-earth { box-shadow: 0 0 12px rgba(139,105,20,0.4), 0 0 24px rgba(139,105,20,0.15); border-color: rgba(139,105,20,0.35); }
.neon-border-volt { box-shadow: 0 0 12px rgba(250,204,21,0.4), 0 0 24px rgba(250,204,21,0.15); border-color: rgba(250,204,21,0.35); }
.neon-border-cosmos { box-shadow: 0 0 12px rgba(192,192,255,0.45), 0 0 24px rgba(192,192,255,0.15); border-color: rgba(192,192,255,0.35); }
.screen-enter { animation: fadeSlideIn 0.45s ease-out both; }
.screen-exit { animation: fadeSlideOut 0.35s ease-in both; }
@keyframes fadeSlideIn {
from { opacity: 0; transform: translateY(18px) scale(0.985); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes fadeSlideOut {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(-12px); }
}
.shake { animation: shake 0.35s ease; }
@keyframes shake {
0%,100%{transform:translateX(0)} 10%{transform:translateX(-6px)} 30%{transform:translateX(5px)} 50%{transform:translateX(-4px)} 70%{transform:translateX(3px)} 90%{transform:translateX(-2px)}
}
.flash { animation: flash 0.25s ease; }
@keyframes flash {
0%{filter:brightness(1)} 40%{filter:brightness(2.5)} 100%{filter:brightness(1)}
}
.bounce { animation: bounce 1.6s ease-in-out infinite; }
@keyframes bounce {
0%,100%{transform:translateY(0)} 45%{transform:translateY(-6px)}
}
.particle-drift {
position: absolute; width: 8px; height: 8px; border-radius: 50%; opacity: 0.6;
animation: drift 3s linear infinite;
}
@keyframes drift {
0%{transform:translateY(0) translateX(0); opacity:0.6} 100%{transform:translateY(-60px) translateX(20px); opacity:0}
}
.hp-bar-fill { transition: width 0.4s ease, background-color 0.3s ease; }
.gradient-text {
background: linear-gradient(135deg, #f0ecf5 20%, #7c3aed 80%);
-webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
}
.btn-glass {
background: rgba(255,255,255,0.05);
border: 1px solid rgba(255,255,255,0.12);
border-radius: 0.75rem;
padding: 0.65rem 1.25rem;
color: var(--text-primary);
font-family: 'Inter', sans-serif;
font-weight: 600;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.2s ease;
backdrop-filter: blur(6px);
}
.btn-glass:hover { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.25); transform: translateY(-1px); }
.btn-glass:active { transform: translateY(0); }
.node-trail { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; }
.node-trail .node-btn {
width: 80px; height: 80px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 0.75rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em;
border: 2px solid rgba(255,255,255,0.1); background: rgba(255,255,255,0.03);
transition: all 0.25s ease; cursor: pointer; color: var(--text-primary);
}
.node-trail .node-btn:hover { transform: scale(1.08); border-color: rgba(255,255,255,0.3); box-shadow: 0 0 18px rgba(255,255,255,0.08); }
.node-btn.encounter { border-color: rgba(34,197,94,0.45); box-shadow: 0 0 10px rgba(34,197,94,0.15); }
.node-btn.mystery { border-color: rgba(250,204,21,0.45); box-shadow: 0 0 10px rgba(250,204,21,0.15); }
.node-btn.battle { border-color: rgba(255,80,47,0.45); box-shadow: 0 0 10px rgba(255,80,47,0.15); }
.node-btn.heal { border-color: rgba(59,130,246,0.45); box-shadow: 0 0 10px rgba(59,130,246,0.15); }
.node-btn.boss { border-color: rgba(168,85,247,0.55); box-shadow: 0 0 18px rgba(168,85,247,0.3); animation: pulse-boss 2s infinite; }
@keyframes pulse-boss { 0%,100%{box-shadow:0 0 18px rgba(168,85,247,0.3)} 50%{box-shadow:0 0 28px rgba(168,85,247,0.5)} }
</style>
</head>
<body>
<div id="app" class="min-h-screen w-full relative">
<!-- Main Menu -->
<section id="screen-menu" class="screen-enter absolute inset-0 flex flex-col items-center justify-center z-50">
<div class="text-center mb-10">
<h1 class="font-['Orbitron'] text-6xl md:text-8xl font-black tracking-tighter mb-2 gradient-text drop-shadow-2xl">AETHELGARD</h1>
<p class="text-xl md:text-2xl text-violet-300 tracking-[0.2em] uppercase font-light">Resonant Chronicles</p>
<div class="w-32 h-1 mx-auto mt-6 rounded-full bg-gradient-to-r from-transparent via-violet-500 to-transparent opacity-60"></div>
</div>
<div class="glass p-8 md:p-10 max-w-md w-full text-center space-y-4 relative overflow-hidden">
<div class="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-violet-500 via-cyan-400 to-amber-400"></div>
<h2 class="text-2xl font-bold mb-2">Welcome, Conductor</h2>
<p class="text-sm text-[var(--text-dim)] mb-6">The harmonic frequencies of Aethelgard await. Capture the 18 Resonants. Master the 4 zones.</p>
<button onclick="startGame()" class="btn-glass w-full text-base py-3 rounded-xl bg-gradient-to-r from-violet-700/40 to-cyan-700/30 border-violet-500/30 hover:scale-[1.02]">Begin Journey</button>
<div class="flex gap-3 justify-center mt-2">
<button onclick="loadSave()" class="btn-glass text-sm py-2 px-4">Continue Save</button>
</div>
<p class="text-xs text-[var(--text-dim)] mt-4">Progress saved automatically to local storage</p>
</div>
</section>
<!-- Overworld / Zone Map -->
<section id="screen-world" class="hidden absolute inset-0 flex flex-col z-40 p-4 md:p-8">
<header class="flex items-center justify-between mb-6">
<div>
<h2 class="font-['Orbitron'] text-3xl font-black tracking-tight">Aethelgard</h2>
<p id="zone-name" class="text-sm text-violet-300 font-medium">Zone: Verdant Canopy</p>
</div>
<div class="flex gap-3 items-center">
<div class="glass px-4 py-2 text-xs flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-amber-400 animate-pulse"></span>
<span><strong id="shard-display">0</strong> Aether Shards</span>
</div>
<button onclick="openDex()" class="btn-glass">Dex</button>
<button onclick="openShop()" class="btn-glass">Camp</button>
<button onclick="openMenuBack()" class="btn-glass text-xs">Menu</button>
</div>
</header>
<main class="flex-1 flex flex-col items-center justify-center">
<div class="glass-card p-8 md:p-10 max-w-3xl w-full">
<h3 class="text-xl font-bold mb-6 text-center">Zone Node Trail</h3>
<p id="zone-desc" class="text-sm text-[var(--text-dim)] text-center mb-6 max-w-lg mx-auto">Navigate through the harmonic nodes. Defeat the Gatekeeper to unlock the next zone.</p>
<div id="node-map" class="node-trail"></div>
</div>
</main>
</section>
<!-- Battle Screen -->
<section id="screen-battle" class="hidden absolute inset-0 z-50 bg-gradient-to-b from-[#0a0912] via-[#140b1e] to-[#080614] overflow-hidden">
<div class="absolute inset-0 z-0" id="battle-bg"></div>
<div class="relative z-10 p-4 md:p-6 h-full flex flex-col">
<div class="flex justify-between items-start mb-4">
<h3 class="font-['Orbitron'] text-xl font-black">Resonance Duel</h3>
<button onclick="fleeBattle()" class="btn-glass text-xs">Flee</button>
</div>
<div class="flex-1 flex flex-col md:flex-row gap-4 md:gap-8 items-start justify-center">
<!-- Player Resonant -->
<div class="glass-card w-full md:w-80 p-5 relative">
<div class="flex items-center gap-3 mb-3">
<div id="player-sprite" class="w-16 h-16 rounded-xl overflow-hidden flex items-center justify-center bg-gradient-to-br from-violet-900/40 to-violet-600/30"></div>
<div>
<h4 id="player-name" class="font-bold text-lg">Conductor</h4>
<span id="player-type" class="text-xs px-2 py-0.5 rounded-full bg-violet-500/20 text-violet-300">Cosmos</span>
</div>
</div>
<div class="mb-1 flex justify-between text-xs"><span>HP</span><span id="player-hp-text">100/100</span></div>
<div class="h-4 w-full rounded-full bg-black/30 overflow-hidden mb-3">
<div id="player-hp-bar" class="hp-bar-fill h-full w-full rounded-full bg-gradient-to-r from-emerald-400 to-emerald-600"></div>
</div>
<div class="flex justify-between text-xs text-[var(--text-dim)]"><span>Lv. <span id="player-level">1</span></span><span>XP <span id="player-xp">0</span>/<span id="player-xp-next">100</span></span></div>
<div id="player-status" class="mt-2 text-xs h-4"></div>
</div>
<!-- Enemy -->
<div class="glass-card w-full md:w-80 p-5 relative">
<div class="flex items-center gap-3 mb-3">
<div id="enemy-sprite" class="w-16 h-16 rounded-xl overflow-hidden flex items-center justify-center bg-gradient-to-br from-red-900/40 to-red-600/30"></div>
<div>
<h4 id="enemy-name" class="font-bold text-lg">Wild Resonant</h4>
<span id="enemy-type" class="text-xs px-2 py-0.5 rounded-full bg-red-500/20 text-red-300">Pyro</span>
</div>
</div>
<div class="mb-1 flex justify-between text-xs"><span>HP</span><span id="enemy-hp-text">100/100</span></div>
<div class="h-4 w-full rounded-full bg-black/30 overflow-hidden mb-3">
<div id="enemy-hp-bar" class="hp-bar-fill h-full w-full rounded-full bg-gradient-to-r from-rose-400 to-rose-600"></div>
</div>
<div class="flex justify-between text-xs text-[var(--text-dim)]"><span>Lv. <span id="enemy-level">1</span></span></div>
<div id="enemy-status" class="mt-2 text-xs h-4"></div>
</div>
</div>
<div class="glass mt-4 p-3 h-24 overflow-y-auto text-sm" id="battle-log"><div class="text-[var(--text-dim)]">The battle begins...</div></div>
<div id="battle-actions" class="grid grid-cols-2 md:grid-cols-4 gap-2 mt-4">
<button onclick="battleAttack()" class="btn-glass text-sm">Attack</button>
<button onclick="battlePrism()" class="btn-glass text-sm">Aether Prism</button>
<button onclick="battleSwapUI()" class="btn-glass text-sm">Exchange</button>
<button onclick="battleItemUI()" class="btn-glass text-sm">Item</button>
</div>
</div>
</section>
<!-- Dex / Encyclopedia -->
<section id="screen-dex" class="hidden absolute inset-0 z-40 p-4 md:p-8 overflow-y-auto">
<div class="max-w-5xl mx-auto">
<div class="flex justify-between items-center mb-6">
<h2 class="font-['Orbitron'] text-3xl font-black">Conductors Dex</h2>
<button onclick="closeDex()" class="btn-glass">Back</button>
</div>
<div id="dex-grid" class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4"></div>
</div>
</section>
<!-- Shop -->
<section id="screen-shop" class="hidden absolute inset-0 z-40 p-4 md:p-8 flex flex-col">
<div class="max-w-3xl mx-auto w-full">
<div class="flex justify-between items-center mb-6">
<h2 class="font-['Orbitron'] text-3xl font-black">Camp Shop</h2>
<button onclick="closeShop()" class="btn-glass">Back</button>
</div>
<div class="glass-card p-6 mb-6">
<p class="text-sm text-[var(--text-dim)]">Spend Aether Shards to purchase harmonic supplies.</p>
<p class="text-lg font-bold mt-1"><span id="shop-shards">0</span> Shards Available</p>
</div>
<div id="shop-items" class="grid grid-cols-1 md:grid-cols-2 gap-4"></div>
</div>
</section>
<!-- Inventory / Exchange -->
<section id="screen-inventory" class="hidden absolute inset-0 z-40 p-4 md:p-8 flex flex-col">
<div class="max-w-3xl mx-auto w-full">
<div class="flex justify-between items-center mb-6">
<h2 class="font-['Orbitron'] text-2xl font-black">Inventory & Exchange</h2>
<button onclick="closeInventory()" class="btn-glass">Back</button>
</div>
<div id="party-display" class="grid grid-cols-3 gap-3 mb-6"></div>
</div>
</section>
<!-- Save / Reset Overlay -->
<section id="screen-saveoverlay" class="hidden absolute inset-0 z-50 bg-black/60 backdrop-blur-md flex items-center justify-center p-6">
<div class="glass max-w-md w-full p-8 text-center">
<h3 class="text-2xl font-bold mb-4">Reset Progress</h3>
<p class="text-sm text-[var(--text-dim)] mb-6">This will erase all saved data and restart your journey from the beginning.</p>
<div class="flex gap-3 justify-center">
<button onclick="resetProgress()" class="btn-glass bg-red-900/20 border-red-500/30 hover:bg-red-900/30">Confirm Reset</button>
<button onclick="closeSaveOverlay()" class="btn-glass">Cancel</button>
</div>
</div>
</section>
<div id="toast" class="fixed top-4 left-1/2 -translate-x-1/2 z-[60] glass px-6 py-3 rounded-xl text-sm font-semibold opacity-0 transition-opacity duration-300 pointer-events-none">Notification</div>
</div>
<script>
'use strict';
// ── class: Synth ──
class Synth {
constructor() {
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
this.gain = this.ctx.createGain();
this.gain.connect(this.ctx.destination);
}
tone(freq, duration, type = 'square', gainVal = 0.08) {
try {
const osc = this.ctx.createOscillator();
osc.type = type;
osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
const env = this.ctx.createGain();
env.gain.setValueAtTime(gainVal, this.ctx.currentTime);
env.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + duration);
osc.connect(env); env.connect(this.gain);
osc.start(); osc.stop(this.ctx.currentTime + duration);
} catch (e) {}
}
playHover() { this.tone(880, 0.08, 'sine', 0.05); }
playSelect() { this.tone(1100, 0.12, 'triangle', 0.06); }
playHitPhysical() { this.tone(120, 0.2, 'sawtooth', 0.06); this.tone(60, 0.2, 'sine', 0.05); }
playHitElemental() { this.tone(660, 0.15, 'triangle', 0.06); this.tone(880, 0.15, 'triangle', 0.05); }
playLevelUp() { [440, 554, 659, 880].forEach((f, i) => setTimeout(() => this.tone(f, 0.15, 'sine', 0.06), i * 60)); }
playCapture() { this.tone(440, 0.1, 'triangle', 0.05); this.tone(880, 0.15, 'triangle', 0.05); this.tone(1320, 0.2, 'sine', 0.05); }
}
// ── const: RESONANTS ──
const RESONANTS = [
// Pyro Family
{ id: 'emberkit', name: 'Emberkit', type: 'Pyro', tier: 1, level: 1, baseHP: 65, baseAtk: 55, baseDef: 35, baseSpd: 52,
moves: [{name:'Ember Spark', power: 40, accuracy: 0.95, element:'Pyro', unlockLevel:1}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="eg"><stop offset="0%" stop-color="#ff6b35"/><stop offset="100%" stop-color="#a02010"/></radialGradient></defs><circle cx="50" cy="50" r="30" fill="url(#eg)"/><circle cx="38" cy="44" r="6" fill="#ffccaa"/><circle cx="62" cy="44" r="6" fill="#ffccaa"/><polygon points="50,70 40,85 60,85" fill="#ffccaa"/></svg>', evolutionLevel: 8, evolutionTo: 'pyrowolf'
},
{ id: 'pyrowolf', name: 'Pyrowolf', type: 'Pyro', tier: 2, level: 8, baseHP: 110, baseAtk: 95, baseDef: 60, baseSpd: 85,
moves: [{name:'Ember Spark', power: 40, accuracy: 0.95, element:'Pyro', unlockLevel:1}, {name:'Inferno Lash', power: 75, accuracy: 0.9, element:'Pyro', unlockLevel:8}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="pw"><stop offset="0%" stop-color="#ff4500"/><stop offset="100%" stop-color="#6b1205"/></radialGradient></defs><ellipse cx="50" cy="48" rx="32" ry="28" fill="url(#pw)"/><circle cx="38" cy="42" r="6" fill="#ffccaa"/><circle cx="62" cy="42" r="6" fill="#ffccaa"/><polygon points="50,72 42,92 58,92" fill="#ffccaa"/><polygon points="20,30 5,50 20,40" fill="#ff4d00"/></svg>', evolutionLevel: 15, evolutionTo: 'ignisaur'
},
{ id: 'ignisaur', name: 'Ignisaur', type: 'Pyro', tier: 3, level: 15, baseHP: 170, baseAtk: 145, baseDef: 100, baseSpd: 110,
moves: [{name:'Ember Spark', power: 40, accuracy: 0.95, element:'Pyro', unlockLevel:1}, {name:'Inferno Lash', power: 75, accuracy: 0.9, element:'Pyro', unlockLevel:8}, {name:'Solar Eruption', power: 110, accuracy: 0.85, element:'Pyro', unlockLevel:15}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="ig"><stop offset="0%" stop-color="#ff6a00"/><stop offset="100%" stop-color="#4a0e00"/></linearGradient></defs><ellipse cx="50" cy="55" rx="36" ry="30" fill="url(#ig)"/><circle cx="35" cy="46" r="8" fill="#fff0cc"/><circle cx="65" cy="46" r="8" fill="#fff0cc"/><polygon points="50,80 38,100 62,100" fill="#ffccaa"/><polygon points="14,40 5,65 22,50" fill="#ff8c00"/><polygon points="86,40 95,65 78,50" fill="#ff8c00"/></svg>', evolutionLevel: null, evolutionTo: null
},
// Hydro Family
{ id: 'droplet', name: 'Droplet', type: 'Hydro', tier: 1, level: 1, baseHP: 70, baseAtk: 45, baseDef: 50, baseSpd: 48,
moves: [{name:'Splash', power: 40, accuracy: 0.98, element:'Hydro', unlockLevel:1}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="dr"><stop offset="0%" stop-color="#4fc3f7"/><stop offset="100%" stop-color="#0a5a8a"/></radialGradient></defs><circle cx="50" cy="48" r="28" fill="url(#dr)"/><ellipse cx="48" cy="52" rx="4" ry="8" fill="#a0e8ff"/><circle cx="38" cy="42" r="5" fill="#e0f7ff"/><circle cx="62" cy="42" r="5" fill="#e0f7ff"/></svg>', evolutionLevel: 8, evolutionTo: 'geoxus'
},
{ id: 'geoxus', name: 'Geoxus', type: 'Hydro', tier: 2, level: 8, baseHP: 115, baseAtk: 80, baseDef: 85, baseSpd: 75,
moves: [{name:'Splash', power: 40, accuracy: 0.98, element:'Hydro', unlockLevel:1}, {name:'Tidal Crash', power: 80, accuracy: 0.85, element:'Hydro', unlockLevel:8}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="gx"><stop offset="0%" stop-color="#1a8fff"/><stop offset="100%" stop-color="#003a66"/></linearGradient></defs><ellipse cx="50" cy="50" rx="34" ry="26" fill="url(#gx)"/><circle cx="36" cy="44" r="7" fill="#d0f0ff"/><circle cx="64" cy="44" r="7" fill="#d0f0ff"/><ellipse cx="50" cy="65" rx="10" ry="6" fill="#a0e8ff"/></svg>', evolutionLevel: 15, evolutionTo: 'neptunian'
},
{ id: 'neptunian', name: 'Neptunian', type: 'Hydro', tier: 3, level: 15, baseHP: 175, baseAtk: 125, baseDef: 120, baseSpd: 105,
moves: [{name:'Splash', power: 40, accuracy: 0.98, element:'Hydro', unlockLevel:1}, {name:'Tidal Crash', power: 80, accuracy: 0.85, element:'Hydro', unlockLevel:8}, {name:'Abyssal Vortex', power: 115, accuracy: 0.8, element:'Hydro', unlockLevel:15}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="np"><stop offset="0%" stop-color="#00bfff"/><stop offset="100%" stop-color="#001f3f"/></radialGradient></defs><ellipse cx="50" cy="52" rx="38" ry="28" fill="url(#np)"/><circle cx="32" cy="44" r="9" fill="#e0faff"/><circle cx="68" cy="44" r="9" fill="#e0faff"/><polygon points="50,82 42,102 58,102" fill="#00aaff"/></svg>', evolutionLevel: null, evolutionTo: null
},
// Flora Family
{ id: 'seedling', name: 'Seedling', type: 'Flora', tier: 1, level: 1, baseHP: 68, baseAtk: 48, baseDef: 40, baseSpd: 55,
moves: [{name:'Vine Whip', power: 45, accuracy: 0.95, element:'Flora', unlockLevel:1}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="sl"><stop offset="0%" stop-color="#66cc66"/><stop offset="100%" stop-color="#0a4a0a"/></radialGradient></defs><circle cx="50" cy="52" r="28" fill="url(#sl)"/><ellipse cx="50" cy="48" rx="6" ry="10" fill="#99ff99"/><circle cx="42" cy="58" r="5" fill="#66dd66"/><circle cx="58" cy="58" r="5" fill="#66dd66"/></svg>', evolutionLevel: 8, evolutionTo: 'thornback'
},
{ id: 'thornback', name: 'Thornback', type: 'Flora', tier: 2, level: 8, baseHP: 120, baseAtk: 90, baseDef: 75, baseSpd: 80,
moves: [{name:'Vine Whip', power: 45, accuracy: 0.95, element:'Flora', unlockLevel:1}, {name:'Thorn Barrage', power: 75, accuracy: 0.85, element:'Flora', unlockLevel:8}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="tb"><stop offset="0%" stop-color="#44aa44"/><stop offset="100%" stop-color="#0f3a0f"/></linearGradient></defs><ellipse cx="50" cy="48" rx="32" ry="30" fill="url(#tb)"/><polygon points="50,25 42,12 58,12" fill="#55bb55"/><circle cx="36" cy="50" r="8" fill="#88dd88"/><circle cx="64" cy="50" r="8" fill="#88dd88"/></svg>', evolutionLevel: 15, evolutionTo: 'bloomgoliath'
},
{ id: 'bloomgoliath', name: 'Bloomgoliath', type: 'Flora', tier: 3, level: 15, baseHP: 180, baseAtk: 135, baseDef: 115, baseSpd: 90,
moves: [{name:'Vine Whip', power: 45, accuracy: 0.95, element:'Flora', unlockLevel:1}, {name:'Thorn Barrage', power: 75, accuracy: 0.85, element:'Flora', unlockLevel:8}, {name:'Flora Colossus', power: 110, accuracy: 0.8, element:'Flora', unlockLevel:15}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="bg"><stop offset="0%" stop-color="#55bb55"/><stop offset="100%" stop-color="#143314"/></radialGradient></defs><ellipse cx="50" cy="48" rx="36" ry="32" fill="url(#bg)"/><polygon points="50,18 42,5 58,5" fill="#77cc77"/><circle cx="30" cy="48" r="10" fill="#99ee99"/><circle cx="70" cy="48" r="10" fill="#99ee99"/><polygon points="50,82 36,95 64,95" fill="#66aa66"/></svg>', evolutionLevel: null, evolutionTo: null
},
// Zephyr Family
{ id: 'gusty', name: 'Gusty', type: 'Zephyr', tier: 1, level: 1, baseHP: 60, baseAtk: 58, baseDef: 32, baseSpd: 65,
moves: [{name:'Gust', power: 40, accuracy: 0.95, element:'Zephyr', unlockLevel:1}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="gu"><stop offset="0%" stop-color="#b388ff"/><stop offset="100%" stop-color="#4a1a80"/></radialGradient></defs><circle cx="50" cy="50" r="28" fill="url(#gu)"/><ellipse cx="50" cy="40" rx="8" ry="4" fill="#d4b4ff"/><circle cx="38" cy="55" r="6" fill="#e0ccff"/><circle cx="62" cy="55" r="6" fill="#e0ccff"/></svg>', evolutionLevel: 8, evolutionTo: 'slipstream'
},
{ id: 'slipstream', name: 'Slipstream', type: 'Zephyr', tier: 2, level: 8, baseHP: 105, baseAtk: 100, baseDef: 55, baseSpd: 100,
moves: [{name:'Gust', power: 40, accuracy: 0.95, element:'Zephyr', unlockLevel:1}, {name:'Sky Shear', power: 80, accuracy: 0.85, element:'Zephyr', unlockLevel:8}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="ss"><stop offset="0%" stop-color="#9a6aff"/><stop offset="100%" stop-color="#2d0f5c"/></linearGradient></defs><ellipse cx="50" cy="48" rx="34" ry="26" fill="url(#ss)"/><ellipse cx="50" cy="36" rx="10" ry="4" fill="#caa0ff"/><circle cx="34" cy="52" r="7" fill="#d0b8ff"/><circle cx="66" cy="52" r="7" fill="#d0b8ff"/></svg>', evolutionLevel: 15, evolutionTo: 'zephyrus'
},
{ id: 'zephyrus', name: 'Zephyrus', type: 'Zephyr', tier: 3, level: 15, baseHP: 160, baseAtk: 145, baseDef: 85, baseSpd: 130,
moves: [{name:'Gust', power: 40, accuracy: 0.95, element:'Zephyr', unlockLevel:1}, {name:'Sky Shear', power: 80, accuracy: 0.85, element:'Zephyr', unlockLevel:8}, {name:'Tempest Burst', power: 115, accuracy: 0.8, element:'Zephyr', unlockLevel:15}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="ze"><stop offset="0%" stop-color="#aa77ff"/><stop offset="100%" stop-color="#2a0640"/></radialGradient></defs><ellipse cx="50" cy="48" rx="38" ry="26" fill="url(#ze)"/><polygon points="50,20 44,8 56,8" fill="#bb88ff"/><circle cx="30" cy="50" r="9" fill="#ccaaff"/><circle cx="70" cy="50" r="9" fill="#ccaaff"/></svg>', evolutionLevel: null, evolutionTo: null
},
// Earth Family
{ id: 'pebble', name: 'Pebble', type: 'Earth', tier: 1, level: 1, baseHP: 72, baseAtk: 42, baseDef: 58, baseSpd: 35,
moves: [{name:'Stone Throw', power: 42, accuracy: 0.95, element:'Earth', unlockLevel:1}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="pb"><stop offset="0%" stop-color="#bfa55a"/><stop offset="100%" stop-color="#5c3a0a"/></radialGradient></defs><circle cx="50" cy="52" r="28" fill="url(#pb)"/><circle cx="38" cy="48" r="6" fill="#e0c080"/><circle cx="62" cy="48" r="6" fill="#e0c080"/><polygon points="50,78 40,92 60,92" fill="#d0a050"/></svg>', evolutionLevel: 8, evolutionTo: 'obsidian'
},
{ id: 'obsidian', name: 'Obsidian', type: 'Earth', tier: 2, level: 8, baseHP: 125, baseAtk: 85, baseDef: 100, baseSpd: 55,
moves: [{name:'Stone Throw', power: 42, accuracy: 0.95, element:'Earth', unlockLevel:1}, {name:'Rock Slide', power: 80, accuracy: 0.9, element:'Earth', unlockLevel:8}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="ob"><stop offset="0%" stop-color="#7a5a2a"/><stop offset="100%" stop-color="#2a150a"/></linearGradient></defs><ellipse cx="50" cy="50" rx="34" ry="28" fill="url(#ob)"/><polygon points="50,22 40,10 60,10" fill="#8a6a3a"/><circle cx="36" cy="48" r="8" fill="#c0a070"/><circle cx="64" cy="48" r="8" fill="#c0a070"/></svg>', evolutionLevel: 15, evolutionTo: 'terrasunder'
},
{ id: 'terrasunder', name: 'Terrasunder', type: 'Earth', tier: 3, level: 15, baseHP: 190, baseAtk: 125, baseDef: 140, baseSpd: 70,
moves: [{name:'Stone Throw', power: 42, accuracy: 0.95, element:'Earth', unlockLevel:1}, {name:'Rock Slide', power: 80, accuracy: 0.9, element:'Earth', unlockLevel:8}, {name:'Seismic Rupture', power: 110, accuracy: 0.8, element:'Earth', unlockLevel:15}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="ts"><stop offset="0%" stop-color="#8a6a3a"/><stop offset="100%" stop-color="#1a0d04"/></radialGradient></defs><ellipse cx="50" cy="48" rx="38" ry="30" fill="url(#ts)"/><polygon points="50,18 42,5 58,5" fill="#a88a5a"/><circle cx="32" cy="46" r="9" fill="#d0b080"/><circle cx="68" cy="46" r="9" fill="#d0b080"/></svg>', evolutionLevel: null, evolutionTo: null
},
// Volt Family
{ id: 'sparky', name: 'Sparky', type: 'Volt', tier: 1, level: 1, baseHP: 62, baseAtk: 60, baseDef: 30, baseSpd: 70,
moves: [{name:'Spark', power: 40, accuracy: 0.95, element:'Volt', unlockLevel:1}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="sp"><stop offset="0%" stop-color="#f0e030"/><stop offset="100%" stop-color="#8a7010"/></radialGradient></defs><circle cx="50" cy="50" r="26" fill="url(#sp)"/><polygon points="50,30 42,18 58,18" fill="#ffee55"/><circle cx="38" cy="52" r="7" fill="#ffeeaa"/><circle cx="62" cy="52" r="7" fill="#ffeeaa"/></svg>', evolutionLevel: 8, evolutionTo: 'boltsaber'
},
{ id: 'boltsaber', name: 'Boltsaber', type: 'Volt', tier: 2, level: 8, baseHP: 108, baseAtk: 105, baseDef: 55, baseSpd: 110,
moves: [{name:'Spark', power: 40, accuracy: 0.95, element:'Volt', unlockLevel:1}, {name:'Volt Slash', power: 80, accuracy: 0.85, element:'Volt', unlockLevel:8}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="bs"><stop offset="0%" stop-color="#ffe030"/><stop offset="100%" stop-color="#8a6a10"/></linearGradient></defs><ellipse cx="50" cy="48" rx="32" ry="24" fill="url(#bs)"/><polygon points="50,22 42,10 58,10" fill="#ffee55"/><circle cx="34" cy="48" r="8" fill="#ffeeaa"/><circle cx="66" cy="48" r="8" fill="#ffeeaa"/></svg>', evolutionLevel: 15, evolutionTo: 'stormlord'
},
{ id: 'stormlord', name: 'Stormlord', type: 'Volt', tier: 3, level: 15, baseHP: 168, baseAtk: 150, baseDef: 90, baseSpd: 135,
moves: [{name:'Spark', power: 40, accuracy: 0.95, element:'Volt', unlockLevel:1}, {name:'Volt Slash', power: 80, accuracy: 0.85, element:'Volt', unlockLevel:8}, {name:'Thunderstorm', power: 115, accuracy: 0.8, element:'Volt', unlockLevel:15}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="sl"><stop offset="0%" stop-color="#ffee55"/><stop offset="100%" stop-color="#4a3008"/></radialGradient></defs><ellipse cx="50" cy="48" rx="36" ry="26" fill="url(#sl)"/><polygon points="50,18 44,6 56,6" fill="#ffeeaa"/><circle cx="32" cy="46" r="9" fill="#ffeeee"/><circle cx="68" cy="46" r="9" fill="#ffeeee"/></svg>', evolutionLevel: null, evolutionTo: null
},
// Cosmos Family
{ id: 'astralshard', name: 'Astral Shard', type: 'Cosmos', tier: 3, level: 15, baseHP: 155, baseAtk: 110, baseDef: 95, baseSpd: 95,
moves: [{name:'Star Pulse', power: 55, accuracy: 0.9, element:'Cosmos', unlockLevel:1}, {name:'Void Rift', power: 90, accuracy: 0.85, element:'Cosmos', unlockLevel:8}, {name:'Nebula Collapse', power: 120, accuracy: 0.75, element:'Cosmos', unlockLevel:15}],
spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="as"><stop offset="0%" stop-color="#e0e0ff"/><stop offset="100%" stop-color="#2a1a4a"/></radialGradient></defs><circle cx="50" cy="48" r="28" fill="url(#as)"/><polygon points="50,28 42,40 58,40" fill="#f0f0ff"/><circle cx="36" cy="48" r="7" fill="#ffffff"/><circle cx="64" cy="48" r="7" fill="#ffffff"/></svg>', evolutionLevel: null, evolutionTo: null
}
];
// ── const: TYPE_ADVANTAGE ──
const TYPE_ADVANTAGE = {
'Pyro': { strong: 'Flora', weak: 'Hydro' },
'Hydro': { strong: 'Pyro', weak: 'Flora' },
'Flora': { strong: 'Hydro', weak: 'Pyro' },
'Zephyr': { strong: 'Earth', weak: 'Volt' },
'Earth': { strong: 'Volt', weak: 'Zephyr' },
'Volt': { strong: 'Zephyr', weak: 'Earth' },
'Cosmos': { strong: null, weak: null }
};
// ── const: ZONES ──
const ZONES = [
{ id: 1, name: 'Verdant Canopy', levels: '1-5', desc: 'Thick harmonic vines pulse with Flora and Zephyr energy. The air is thick with pollen and static.', types: ['Flora','Zephyr'], gatekeeper: { id: 'thornback', level: 5 } },
{ id: 2, name: 'Sunken Grotto', levels: '5-10', desc: 'Crystal pools reflect Hydro and Earth frequencies. Echoes ripple through underwater caverns.', types: ['Hydro','Earth'], gatekeeper: { id: 'geoxus', level: 10 } },
{ id: 3, name: 'Obsidian Crags', levels: '10-15', desc: 'Molten fissures crack black stone. Pyro and Volt energies clash in violent storms.', types: ['Pyro','Volt'], gatekeeper: { id: 'boltsaber', level: 15 } },
{ id: 4, name: 'Apex Pillar', levels: '15+', desc: 'The harmonic apex of Aethelgard. Only the strongest Conductors survive its resonance storms.', types: ['Cosmos','Fire','Hydro','Flora','Zephyr','Earth','Volt'], gatekeeper: { id: 'stormlord', level: 18 } }
];
// ── const: SHOP_ITEMS ──
const SHOP_ITEMS = [
{ id: 'hprism', name: 'Harmonizer Prism', desc: 'Basic capture matrix. Increases catch rate to 35%.', price: 25, icon: '◆', effect: (p) => { p.items.push('prism'); } },
{ id: 'hprism2', name: 'Hyper-Prism', desc: 'Advanced geometric capture array. 60% catch rate.', price: 100, icon: '◆◆', effect: (p) => { p.items.push('hyperprism'); } },
{ id: 'restorer', name: 'Core Restorer', desc: 'Restores 50% of max HP to one Resonant.', price: 30, icon: '♥', effect: (p) => { p.items.push('restorer'); } },
{ id: 'cleanser', name: 'Resonance Elixir', desc: 'Cleanses all negative harmonic status effects.', price: 40, icon: '◈', effect: (p) => { p.items.push('cleanser'); } }
];
// ── function: defaultProfile ──
function defaultProfile() {
return {
zoneProgress: 1, unlockedZones: [1], completedBosses: [], shards: 50,
party: [
{ id: 'seedling', level: 1, xp: 0, hp: 70, maxHP: 70, movesUnlocked: [1] }
],
inventory: ['prism','restorer'],
caught: ['seedling'],
activePartyIndex: 0
};
}
// ── function: saveGame ──
function saveGame() {
try { localStorage.setItem('aethelgard_save', JSON.stringify(gameState)); } catch (e) {}
}
// ── function: loadSave ──
function loadSave() {
try {
const raw = localStorage.getItem('aethelgard_save');
if (!raw) throw new Error('No save');
const s = JSON.parse(raw);
Object.assign(gameState, s);
saveGame();
initUI();
showScreen('world');
showToast('Save restored');
synth.playSelect();
} catch (e) {
showToast('No save found');
gameState = defaultProfile();
}
}
// ── function: resetProgress ──
function resetProgress() {
gameState = defaultProfile();
saveGame();
showToast('Progress reset');
closeSaveOverlay();
setTimeout(() => location.reload(), 400);
}
</script>
</body>
</html>
<!-- agent-meta {"model":"thinkingmachines/inkling","provider":"openrouter","persona":"composer","sessionId":"5f34cabe-d63c-41c3-9750-653368c32534","tokensIn":153217,"tokensOut":16949,"tokensTotal":170166,"turns":13,"toolCalls":12,"failedToolCalls":2,"timestamp":"2026-07-21T01:18:23.304Z"} -->