Aethelgard
GPT 5.6 terra · typescript

Browser check: Artifact runtime error. This is a technical check, not a quality review.
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 26,614 bytes · SHA-256 09fcd2b7ac57
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Aethelgard: Resonance Atlas</title>
<style>
/* ── css: game ── */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&family=Press+Start+2P&display=swap');:root{--bg:#090b1a;--panel:rgba(21,24,53,.72);--line:rgba(171,167,255,.23);--ink:#f4f5ff;--muted:#9ca5c9;--violet:#8b7cff;--cyan:#50e5ff;--green:#4ee49a;--yellow:#ffd569;--red:#ff647c}*{box-sizing:border-box}body{margin:0;min-height:100vh;background:radial-gradient(circle at 20% 0%,#28215a 0,transparent 36%),radial-gradient(circle at 90% 100%,#123a4a 0,transparent 38%),var(--bg);color:var(--ink);font-family:Inter,Arial,sans-serif}button{font:inherit;color:inherit;cursor:pointer}#app{min-height:100vh}.shell{width:min(1180px,100%);margin:auto;padding:24px}.glass{background:var(--panel);border:1px solid var(--line);box-shadow:0 20px 60px #0007,inset 0 1px #fff1;backdrop-filter:blur(18px);border-radius:22px}.logo{font:16px 'Press Start 2P',monospace;line-height:1.65;letter-spacing:1px;background:linear-gradient(90deg,#fff,#a7ddff,#c5a5ff);-webkit-background-clip:text;color:transparent}.top{display:flex;align-items:center;justify-content:space-between;gap:18px;margin-bottom:22px}.shards{border:1px solid #ffd56966;color:#ffe29a;padding:9px 13px;border-radius:12px;background:#ffd5690d;font-weight:800}.hero{padding:44px;min-height:590px;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;overflow:hidden;position:relative}.hero:after{content:'✦ ◇ ✦';position:absolute;right:7%;top:18%;font-size:100px;color:#a89eff12;transform:rotate(-12deg)}h1{font-size:clamp(31px,6vw,66px);max-width:760px;margin:16px 0;font-weight:800;line-height:1.02;letter-spacing:-3px}.lead{max-width:650px;color:var(--muted);line-height:1.7;font-size:17px}.btn{border:1px solid #9f98ff88;border-radius:12px;padding:12px 16px;background:linear-gradient(135deg,#7567ed,#a957df);font-weight:800;box-shadow:0 8px 22px #7859de44;transition:.18s}.btn:hover{transform:translateY(-2px);filter:brightness(1.15)}.btn.alt{background:#ffffff0b;border-color:#ffffff1f;box-shadow:none}.btn.danger{background:#7d294b55;border-color:#ff647c77}.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:24px}.layout{display:grid;grid-template-columns:260px 1fr;gap:18px}.side{padding:16px}.profile{padding:15px;border-radius:15px;background:#ffffff08;margin-bottom:14px}.profile b{display:block;font-size:18px}.muted{color:var(--muted);font-size:13px}.nav{display:grid;gap:7px}.nav button{background:transparent;border:0;text-align:left;border-radius:10px;padding:11px}.nav button:hover,.nav button.active{background:#9e91ff1c;color:#d5d0ff}.main{padding:21px;min-height:610px}.heading{display:flex;align-items:end;justify-content:space-between;gap:10px;margin-bottom:20px}.heading h2{margin:0;font-size:25px}.zonecard{padding:18px;margin-bottom:14px;position:relative;overflow:hidden}.zonecard.locked{opacity:.48;filter:saturate(.5)}.zone-head{display:flex;justify-content:space-between;gap:10px}.pill{font-size:11px;padding:5px 8px;border:1px solid #ffffff23;border-radius:999px;color:var(--muted)}.trail{display:flex;align-items:center;justify-content:space-between;margin-top:22px;gap:4px}.node{width:42px;height:42px;border-radius:50%;border:2px solid #8d88ff;background:#171a39;display:grid;place-items:center;font-size:17px;box-shadow:0 0 14px #8d88ff55}.node:not(:disabled):hover{background:#8d88ff;transform:scale(1.12)}.node:disabled{opacity:.4}.line{height:2px;background:#8278ff55;flex:1}.teamgrid,.dexgrid,.shopgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px}.card{padding:14px;border-radius:15px;background:#ffffff08;border:1px solid #ffffff12}.type{font-size:10px;font-weight:800;letter-spacing:1px}.hp{height:8px;background:#0006;border-radius:8px;overflow:hidden;margin:7px 0}.hp i{display:block;height:100%;background:var(--green);border-radius:8px}.sprite{width:82px;height:82px;filter:drop-shadow(0 0 12px var(--glow));}.monster{display:flex;align-items:center;gap:8px}.monster strong{display:block}.battle{min-height:650px;padding:25px;position:relative;overflow:hidden;background:radial-gradient(circle at 77% 18%,#ffffff11,transparent 25%),var(--panel)}.field{height:350px;position:relative;border-radius:20px;background:linear-gradient(160deg,#20204c,#101b35 60%,#174342);overflow:hidden}.field:after{content:'';position:absolute;left:-5%;right:-5%;height:48%;bottom:-25%;border-radius:50% 50% 0 0;background:#28745c66;border-top:2px solid #8effba55}.fighter{position:absolute;z-index:2;width:215px}.fighter.enemy{right:9%;top:24px}.fighter.player{left:8%;bottom:8px}.fighter .sprite{width:145px;height:145px;animation:bob 1.6s ease-in-out infinite}.fighter.enemy .sprite{transform:scaleX(-1)}.battleinfo{padding:12px;border:1px solid #fff2;border-radius:13px;background:#0b1027bb}.fighter.enemy .battleinfo{margin-left:-35px}.fighter.player .battleinfo{margin-right:-35px}.battle-actions{display:grid;grid-template-columns:1.2fr .8fr;gap:14px;margin-top:16px}.moves{display:grid;grid-template-columns:1fr 1fr;gap:8px}.move{padding:10px;text-align:left;background:#ffffff0c;border:1px solid #ffffff1c;border-radius:11px}.move:hover{border-color:var(--cyan);background:#50e5ff12}.move small{display:block;color:var(--muted);margin-top:3px}.combat-tools{display:grid;grid-template-columns:1fr 1fr;gap:8px}.log{margin-top:13px;color:#d9ddff;background:#06091688;padding:11px;border-radius:10px;min-height:44px;font-size:13px}.modal{position:fixed;inset:0;background:#040510bd;z-index:10;display:grid;place-items:center;padding:16px}.modalbox{width:min(500px,100%);padding:23px}.shopitem{padding:14px}.shopitem b{display:block}.toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:#171a36eF;border:1px solid #a9a3ff77;padding:11px 16px;border-radius:10px;z-index:20;animation:in .25s}.hidden{display:none!important}@keyframes bob{50%{transform:translateY(-8px)}}@keyframes in{from{opacity:0;transform:translate(-50%,10px)}}@media(max-width:760px){.shell{padding:13px}.layout{grid-template-columns:1fr}.side{display:flex;gap:10px;overflow:auto}.profile{min-width:175px;margin:0}.nav{display:flex}.nav button{white-space:nowrap}.main{padding:15px}.battle{padding:13px}.field{height:300px}.fighter{width:155px}.fighter .sprite{width:110px;height:110px}.battle-actions{grid-template-columns:1fr}.hero{padding:27px;min-height:600px}h1{letter-spacing:-2px}.top{align-items:flex-start}.top .btn{padding:9px}.trail .node{width:34px;height:34px;font-size:13px}}
</style>
</head>
<body>
<div id="game"></div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {};
function __require(id) {
if (__cache[id]) return __cache[id].exports;
var module = __cache[id] = { exports: {} };
var factory = __mods[id];
if (!factory) throw new Error("Module not found: " + id);
factory(module.exports, function (spec) {
var target = (__map[id] && __map[id][spec]) || spec;
return __require(target);
}, module);
return module.exports;
}
// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const E = ['Pyro', 'Hydro', 'Flora', 'Volt', 'Zephyr', 'Earth'];
const moves = { Pyro: [{ n: 'Cinder Tap', p: 38, a: 100, e: 'Pyro', l: 1 }, { n: 'Flare Claw', p: 58, a: 94, e: 'Pyro', l: 5 }, { n: 'Solar Burst', p: 82, a: 88, e: 'Pyro', l: 10 }, { n: 'Nova Roar', p: 106, a: 82, e: 'Pyro', l: 15 }], Hydro: [{ n: 'Ripple', p: 38, a: 100, e: 'Hydro', l: 1 }, { n: 'Tide Lash', p: 58, a: 95, e: 'Hydro', l: 5 }, { n: 'Aqua Spiral', p: 80, a: 89, e: 'Hydro', l: 10 }, { n: 'Abyss Surge', p: 105, a: 82, e: 'Hydro', l: 15 }], Flora: [{ n: 'Vine Flick', p: 38, a: 100, e: 'Flora', l: 1 }, { n: 'Bramble Snap', p: 58, a: 94, e: 'Flora', l: 5 }, { n: 'Petal Storm', p: 81, a: 88, e: 'Flora', l: 10 }, { n: 'Worldroot', p: 105, a: 82, e: 'Flora', l: 15 }], Volt: [{ n: 'Static Pop', p: 39, a: 100, e: 'Volt', l: 1 }, { n: 'Arc Fang', p: 60, a: 93, e: 'Volt', l: 5 }, { n: 'Thunder Rail', p: 82, a: 88, e: 'Volt', l: 10 }, { n: 'Skybreaker', p: 108, a: 80, e: 'Volt', l: 15 }], Zephyr: [{ n: 'Breeze Cut', p: 38, a: 100, e: 'Zephyr', l: 1 }, { n: 'Gale Wing', p: 57, a: 95, e: 'Zephyr', l: 5 }, { n: 'Cyclone Step', p: 80, a: 89, e: 'Zephyr', l: 10 }, { n: 'Tempest Crown', p: 104, a: 83, e: 'Zephyr', l: 15 }], Earth: [{ n: 'Stone Tap', p: 40, a: 100, e: 'Earth', l: 1 }, { n: 'Fault Strike', p: 60, a: 93, e: 'Earth', l: 5 }, { n: 'Quarry Crush', p: 83, a: 87, e: 'Earth', l: 10 }, { n: 'Continental', p: 108, a: 80, e: 'Earth', l: 15 }] };
const raw = [['emberkit', 'Emberkit', 'Pyro', 1, [38, 12, 9, 13]], ['pyrowolf', 'Pyrowolf', 'Pyro', 2, [57, 20, 15, 22]], ['ignisaur', 'Ignisaur', 'Pyro', 3, [78, 30, 22, 29]], ['droplet', 'Droplet', 'Hydro', 1, [42, 10, 12, 10]], ['geoxus', 'Geoxus', 'Hydro', 2, [61, 17, 21, 17]], ['neptunian', 'Neptunian', 'Hydro', 3, [82, 25, 31, 24]], ['seedling', 'Seedling', 'Flora', 1, [44, 10, 11, 9]], ['thornback', 'Thornback', 'Flora', 2, [64, 18, 18, 15]], ['bloomgoliath', 'Bloomgoliath', 'Flora', 3, [87, 27, 28, 20]], ['sparky', 'Sparky', 'Volt', 1, [36, 13, 8, 15]], ['boltsaber', 'Boltsaber', 'Volt', 2, [54, 22, 14, 25]], ['stormlord', 'Stormlord', 'Volt', 3, [74, 32, 21, 34]], ['gusty', 'Gusty', 'Zephyr', 1, [39, 11, 9, 14]], ['slipstream', 'Slipstream', 'Zephyr', 2, [58, 19, 15, 23]], ['zephyrus', 'Zephyrus', 'Zephyr', 3, [77, 28, 21, 32]], ['pebble', 'Pebble', 'Earth', 1, [48, 12, 14, 7]], ['obsidian', 'Obsidian', 'Earth', 2, [70, 20, 24, 12]], ['terrasunder', 'Terrasunder', 'Earth', 3, [94, 29, 35, 17]]];
const db = raw.map(x => ({ id: x[0], n: x[1], e: x[2], stage: x[3], base: x[4], moves: moves[x[2]] }));
const byId = (id) => db.find(x => x.id === id);
const colors = { Pyro: '#ff715b', Hydro: '#54c9ff', Flora: '#58e39b', Volt: '#ffe36b', Zephyr: '#a5f3e7', Earth: '#d2a36d' };
class Synth {
play(kind) { try {
this.ctx ?? (this.ctx = new AudioContext());
const c = this.ctx, o = c.createOscillator(), g = c.createGain();
o.type = kind === 'hit' ? 'square' : 'triangle';
o.frequency.value = kind === 'win' ? 880 : kind === 'hit' ? 120 : kind === 'element' ? 520 : 350;
g.gain.setValueAtTime(.05, c.currentTime);
g.gain.exponentialRampToValueAtTime(.001, c.currentTime + .14);
o.connect(g).connect(c.destination);
o.start();
o.stop(c.currentTime + .15);
}
catch { } }
}
const sound = new Synth();
const key = 'aethelgard-profile-v1';
const fresh = () => ({ party: [{ id: 'emberkit', level: 5, xp: 0, hp: maxHp({ id: 'emberkit', level: 5, xp: 0, hp: 0, status: '' }), status: '' }], storage: [], shards: 70, inv: { prism: 8, hyper: 1, restorer: 2, elixir: 1 }, zones: 1, bosses: [], seen: ['emberkit'] });
let P;
try {
P = JSON.parse(localStorage.getItem(key) || 'null') || fresh();
}
catch {
P = fresh();
}
const save = () => localStorage.setItem(key, JSON.stringify(P));
function maxHp(m) { const s = byId(m.id); return s.base[0] + m.level * 5 + s.stage * 5; }
function stat(m, i) { const s = byId(m.id); return s.base[i] + m.level * (i === 3 ? 2 : 3) + s.stage * 3; }
function evolution(m) { const s = byId(m.id), want = m.level >= 15 ? 3 : m.level >= 8 ? 2 : 1; if (s.stage !== want) {
const n = db.find(x => x.e === s.e && x.stage === want);
m.id = n.id;
m.hp = maxHp(m);
toast(`${n.n} resonates into a new form!`);
sound.play('win');
} }
function xpNeed(l) { return 35 + l * 25; }
function gain(m, x) { m.xp += x; while (m.level < 20 && m.xp >= xpNeed(m.level)) {
m.xp -= xpNeed(m.level++);
m.hp = maxHp(m);
evolution(m);
sound.play('win');
} }
const zones = [{ n: 'Verdant Canopy', range: 'Levels 1–5 · Flora / Zephyr', desc: 'A living canopy humming with first frequencies.', types: ['Flora', 'Zephyr'], boss: 'Warden Liora', quote: '“Let the canopy judge the rhythm in your heart.”' }, { n: 'Sunken Grotto', range: 'Levels 5–10 · Hydro / Earth', desc: 'Crystal rivers carve paths beneath the old world.', types: ['Hydro', 'Earth'], boss: 'Tidekeeper Mero', quote: '“Every current remembers the stone it shaped.”' }, { n: 'Obsidian Crags', range: 'Levels 10–15 · Pyro / Volt', desc: 'Stormfire scars the blackened mountain trail.', types: ['Pyro', 'Volt'], boss: 'Forgecaller Vex', quote: '“Only a steadfast signal survives the lightning.”' }, { n: 'Apex Pillar', range: 'Level 15+ · Final Gauntlet', desc: 'The skyward spire where all six frequencies converge.', types: ['Pyro', 'Hydro', 'Flora', 'Volt', 'Zephyr', 'Earth'], boss: 'Arch Conductor Sol', quote: '“Tune beyond victory. Become the harmony.”' }];
let screen = 'menu';
let battle = null;
function svg(id, large = false) { const s = byId(id), c = colors[s.e], shape = s.e === 'Pyro' ? '<path d="M48 5C70 35 88 48 69 84 58 104 30 101 22 82 10 52 34 37 48 5Z"/>' : s.e === 'Hydro' ? '<path d="M50 5C76 39 88 58 68 86 54 105 28 99 18 80 5 55 31 31 50 5Z"/>' : s.e === 'Flora' ? '<path d="M50 16C83 8 95 43 69 58 87 84 56 103 48 76 23 97 5 68 31 54 6 29 29 8 50 16Z"/>' : s.e === 'Volt' ? '<path d="M55 5 19 57h25l-7 38 43-57H55Z"/>' : s.e === 'Zephyr' ? '<path d="M9 55c29-43 54-45 77-38-25 10-35 23-40 38 18-10 31-10 45-3-31 28-62 26-82 3Z"/>' : '<path d="M50 7 88 31 78 78 50 98 18 78 11 32Z"/>'; return `<svg class="sprite" style="--glow:${c}" viewBox="0 0 100 105" aria-label="${s.n}"><defs><linearGradient id="g${id}" x2="0" y2="1"><stop stop-color="${c}"/><stop offset="1" stop-color="#382650"/></linearGradient></defs><g fill="url(#g${id})" stroke="${c}" stroke-width="3">${shape}</g><circle cx="38" cy="48" r="5" fill="#fff"/><circle cx="63" cy="48" r="5" fill="#fff"/><path d="M37 68Q50 78 64 67" fill="none" stroke="#fff" stroke-width="3"/></svg>`; }
function hpbar(m) { const pct = Math.max(0, m.hp / maxHp(m) * 100), col = pct > 50 ? '#4ee49a' : pct > 25 ? '#ffd569' : '#ff647c'; return `<div class="hp"><i style="width:${pct}%;background:${col}"></i></div><small>${Math.max(0, m.hp)} / ${maxHp(m)} HP</small>`; }
function monCard(m) { const s = byId(m.id); return `<div class="card monster">${svg(m.id)}<div><strong>${s.n}</strong><span class="type" style="color:${colors[s.e]}">${s.e.toUpperCase()}</span><small> Lv. ${m.level}</small>${hpbar(m)}${m.status ? `<small>${m.status}</small>` : ''}</div></div>`; }
function toast(t) { const x = document.createElement('div'); x.className = 'toast'; x.textContent = t; document.body.append(x); setTimeout(() => x.remove(), 2200); }
function render() { save(); const root = document.querySelector('#game'); if (screen === 'menu') {
root.innerHTML = `<main class="shell"><header class="top"><div class="logo">AETHELGARD<br>RESONANCE ATLAS</div><button class="btn alt" data-a="reset">Reset Progress</button></header><section class="hero glass"><span class="pill">TURN-BASED FREQUENCY RPG</span><h1>Conduct the living music of a new world.</h1><p class="lead">Discover Resonants, tune your three-member ensemble, and rise through four luminous regions toward the Apex Pillar.</p><div class="actions"><button class="btn" data-a="begin">Enter Aethelgard</button><button class="btn alt" data-a="dex">Browse Resonance Dex</button></div></section></main>`;
}
else if (screen === 'battle' && battle)
renderBattle(root);
else {
root.innerHTML = `<main class="shell"><header class="top"><div class="logo">AETHELGARD<br>RESONANCE ATLAS</div><div class="shards">✦ ${P.shards} SHARDS</div></header><div class="layout"><aside class="side glass"><div class="profile"><b>Conductor</b><span class="muted">${P.party.length}/3 active Resonants</span></div><nav class="nav"><button class="${screen === 'world' ? 'active' : ''}" data-a="world">✦ Expedition</button><button class="${screen === 'team' ? 'active' : ''}" data-a="team">◈ Ensemble</button><button class="${screen === 'dex' ? 'active' : ''}" data-a="dex">◌ Resonance Dex</button><button class="${screen === 'shop' ? 'active' : ''}" data-a="shop">✧ Camp Shop</button><button data-a="menu">← Main Menu</button></nav></aside><section class="main glass">${content()}</section></div></main>`;
} bind(); }
function content() { if (screen === 'world')
return `<div class="heading"><div><h2>Expedition Trail</h2><span class="muted">Choose a resonant node to continue your journey.</span></div></div>${zones.map((z, i) => { let open = i < P.zones; return `<article class="zonecard glass ${open ? '' : 'locked'}"><div class="zone-head"><div><b>${i + 1}. ${z.n}</b><p class="muted">${z.desc}</p></div><span class="pill">${z.range}</span></div><div class="trail">${['🌿', '◇', '⚔', '♨', '♛'].map((x, n) => `${n ? '<span class="line"></span>' : ''}<button ${open ? '' : 'disabled'} class="node" data-node="${i}:${n}" title="${['Wild resonance', 'Mystery cache', 'Wandering conductor', 'Healing spring', 'Gatekeeper'][n]}">${x}</button>`).join('')}</div></article>`; }).join('')}`; if (screen === 'team')
return `<div class="heading"><div><h2>Your Ensemble</h2><span class="muted">Exchange during battle from this active trio.</span></div></div><div class="teamgrid">${P.party.map(monCard).join('')}</div><h3>Resonance Vault</h3><div class="teamgrid">${P.storage.length ? P.storage.map(monCard).join('') : '<p class="muted">No stored Resonants yet. Aether Prisms await a worthy frequency.</p>'}</div>`; if (screen === 'dex')
return `<div class="heading"><div><h2>Conductors Dex</h2><span class="muted">${P.seen.length}/18 frequencies observed</span></div></div><div class="dexgrid">${db.map(s => { const seen = P.seen.includes(s.id); return `<div class="card">${seen ? svg(s.id) : '<div style="height:82px;font-size:44px;color:#515570;display:grid;place-items:center">?</div>'}<b>${seen ? s.n : 'Unknown Resonance'}</b><div class="type" style="color:${colors[s.e]}">${seen ? s.e : 'UNSCANNED'}</div><small class="muted">${seen ? `Evolution tier ${s.stage} · Base HP ${s.base[0]}` : 'Tune this signal in the wild.'}</small></div>`; }).join('')}</div>`; return `<div class="heading"><div><h2>Camp Shop</h2><span class="muted">Supplies resonate best before a long trail.</span></div></div><div class="shopgrid">${[['prism', 'Harmonizer Prism', 25, 'Reliable wild capture matrix'], ['hyper', 'Hyper-Conductive Prism', 90, 'Powerful high-catch crystal'], ['restorer', 'Core Restorer', 35, 'Restore 50% active HP'], ['elixir', 'Resonance Elixir', 30, 'Cleanse all unstable status']].map(x => `<div class="card shopitem"><b>${x[1]}</b><p class="muted">${x[3]}</p><span class="pill">Owned ${P.inv[x[0]] || 0}</span><div class="actions"><button class="btn alt" data-buy="${x[0]}:${x[2]}">✦ ${x[2]}</button></div></div>`).join('')}</div>`; }
function renderBattle(root) { const b = battle, a = P.party[0], en = byId(b.enemy.id), as = byId(a.id); root.innerHTML = `<main class="shell"><section class="battle glass"><header class="top"><div class="logo">${b.boss ? 'GATEKEEPER TUNING' : 'WILD FREQUENCY'}</div><button class="btn alt" data-a="flee">Retreat</button></header><div class="field"><div class="fighter enemy"><div class="battleinfo"><b>${en.n} <small>Lv.${b.enemy.level}</small></b><div class="type" style="color:${colors[en.e]}">${en.e}</div>${hpbar(b.enemy)}</div>${svg(b.enemy.id)}</div><div class="fighter player">${svg(a.id)}<div class="battleinfo"><b>${as.n} <small>Lv.${a.level}</small></b><div class="type" style="color:${colors[as.e]}">${as.e} ${a.status}</div>${hpbar(a)}<small>XP ${a.xp}/${xpNeed(a.level)}</small></div></div></div><div class="battle-actions"><div class="moves">${as.moves.filter(m => m.l <= a.level).map((m, i) => `<button class="move" data-move="${i}"><b>${m.n}</b><small style="color:${colors[m.e]}">${m.e} · ${m.p} PWR · ${m.a}%</small></button>`).join('')}</div><div class="combat-tools"><button class="btn alt" data-tool="prism">Prisms (${P.inv.prism || 0})</button><button class="btn alt" data-tool="hyper">Hyper (${P.inv.hyper || 0})</button><button class="btn alt" data-tool="restorer">Restore</button><button class="btn alt" data-tool="exchange">Exchange</button></div></div><div class="log">${b.log}</div></section></main>`; bind(); }
function bind() { document.querySelectorAll('[data-a]').forEach(x => x.onclick = () => act(x.dataset.a)); document.querySelectorAll('[data-node]').forEach(x => x.onclick = () => node(x.dataset.node)); document.querySelectorAll('[data-move]').forEach(x => x.onclick = () => attack(+x.dataset.move)); document.querySelectorAll('[data-tool]').forEach(x => x.onclick = () => tool(x.dataset.tool)); document.querySelectorAll('[data-buy]').forEach(x => x.onclick = () => { const [id, c] = x.dataset.buy.split(':'); let cost = +c; if (P.shards < cost)
return toast('Not enough Aether Shards.'); P.shards -= cost; P.inv[id] = (P.inv[id] || 0) + 1; sound.play('win'); render(); }); }
function act(a) { if (a === 'reset') {
localStorage.removeItem(key);
P = fresh();
toast('New resonance profile initialized.');
return render();
} if (a === 'begin' || a === 'world')
screen = 'world';
else if (a === 'flee') {
battle = null;
screen = 'world';
}
else
screen = a; render(); }
function node(v) { let [z, n] = v.split(':').map(Number), zone = zones[z]; if (n === 1) {
P.shards += 20 + z * 10;
toast('Mystery cache: Aether Shards recovered!');
sound.play('win');
return render();
} if (n === 3) {
P.party.forEach(m => { m.hp = maxHp(m); m.status = ''; });
toast('Healing spring restored your ensemble.');
sound.play('win');
return render();
} let wild = n === 0; if (n === 4 && P.bosses.includes(z)) {
toast('This gatekeeper is already harmonized.');
return;
} let choices = db.filter(s => zone.types.includes(s.e) && s.stage <= Math.min(3, z + 1)); let sp = choices[Math.floor(Math.random() * choices.length)], lv = n === 4 ? Math.max(5, z * 5 + 5) : Math.max(2, z * 4 + 2 + Math.floor(Math.random() * 3)); battle = { enemy: { id: sp.id, level: lv, xp: 0, hp: 0, status: '' }, wild, zone: z, boss: n === 4, log: n === 4 ? `${zone.boss}: ${zone.quote}` : `A wild ${sp.n} pulses into view!` }; battle.enemy.hp = maxHp(battle.enemy); P.seen.push(sp.id); P.seen = [...new Set(P.seen)]; screen = 'battle'; sound.play('element'); render(); }
function modifier(a, d) { let win = { Pyro: 'Flora', Hydro: 'Pyro', Flora: 'Hydro', Volt: 'Zephyr', Zephyr: 'Earth', Earth: 'Volt' }; if (win[a] === d)
return 1.55; if (win[d] === a)
return .68; return 1; }
function enemyTurn() { if (!battle)
return; let a = P.party[0], e = battle.enemy; if (a.hp <= 0)
return; let available = byId(e.id).moves.filter(x => x.l <= e.level); let m = available[available.length - 1]; let dmg = Math.max(1, Math.floor((((2 * e.level / 5 + 2) * m.p * (stat(e, 1) / stat(a, 2))) / 50 + 2) * modifier(m.e, byId(a.id).e) * (.85 + Math.random() * .15))); a.hp -= dmg; battle.log += ` ${byId(e.id).n} answers with ${m.n}: ${dmg} damage.`; sound.play('hit'); if (a.hp <= 0) {
a.hp = 0;
let next = P.party.find(x => x.hp > 0);
if (next) {
P.party = [next, ...P.party.filter(x => x !== next)];
battle.log += ' Your ensemble shifts its lead.';
}
else {
P.party.forEach(x => x.hp = Math.ceil(maxHp(x) * .5));
battle = null;
screen = 'world';
toast('Your signal faded — camp recovery engaged.');
}
} }
function attack(i) { if (!battle)
return; let a = P.party[0], m = byId(a.id).moves.filter(x => x.l <= a.level)[i]; if (!m)
return; if (Math.random() * 100 > m.a) {
battle.log = `${byId(a.id).n}'s ${m.n} slipped out of tune!`;
enemyTurn();
render();
return;
} let crit = Math.random() < .1, d = Math.max(1, Math.floor((((2 * a.level / 5 + 2) * m.p * (stat(a, 1) / stat(battle.enemy, 2))) / 50 + 2) * modifier(m.e, byId(battle.enemy.id).e) * (.85 + Math.random() * .15) * (crit ? 1.5 : 1))); battle.enemy.hp -= d; battle.log = `${byId(a.id).n} performs ${m.n}: ${d} damage${crit ? ' · CRITICAL!' : ''}.`; sound.play(modifier(m.e, byId(battle.enemy.id).e) > 1 ? 'element' : 'hit'); if (battle.enemy.hp <= 0)
return victory(); enemyTurn(); render(); }
function victory() { if (!battle)
return; let b = battle, a = P.party[0], reward = 18 + b.enemy.level * 7 + (b.boss ? 80 : 0); gain(a, 28 + b.enemy.level * 12); P.shards += reward; if (b.boss) {
P.bosses.push(b.zone);
P.bosses = [...new Set(P.bosses)];
P.zones = Math.max(P.zones, Math.min(4, b.zone + 2));
toast(`${zones[b.zone].boss} harmonized! New trail unlocked.`);
}
else
toast(`Frequency dispersed. +${reward} shards.`); sound.play('win'); battle = null; screen = 'world'; render(); }
function tool(t) { if (!battle)
return; let a = P.party[0]; if (t === 'exchange') {
let i = P.party.findIndex((x, i) => i > 0 && x.hp > 0);
if (i < 0)
return toast('No conscious Resonant to exchange.');
[P.party[0], P.party[i]] = [P.party[i], P.party[0]];
battle.log = 'Ensemble frequency exchanged.';
enemyTurn();
return render();
} if (t === 'restorer') {
if (!(P.inv.restorer || 0))
return toast('No Core Restorers.');
P.inv.restorer--;
a.hp = Math.min(maxHp(a), a.hp + Math.ceil(maxHp(a) / 2));
battle.log = 'Core Restorer restores your resonance.';
sound.play('win');
enemyTurn();
return render();
} if (!battle.wild)
return toast('Gatekeepers cannot be captured.'); if (!(P.inv[t] || 0))
return toast('No prism of that type.'); P.inv[t]--; let chance = (1 - battle.enemy.hp / maxHp(battle.enemy)) * .65 + (t === 'hyper' ? .45 : .18); if (Math.random() < chance) {
let caught = battle.enemy;
P.seen.push(caught.id);
if (P.party.length < 3)
P.party.push(caught);
else
P.storage.push(caught);
toast(`${byId(caught.id).n} harmonized into your collection!`);
sound.play('win');
battle = null;
screen = 'world';
render();
}
else {
battle.log = 'The prism fractures into harmless light — almost!';
sound.play('hit');
enemyTurn();
render();
} }
render();
};
// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"openai/gpt-5.6-terra","provider":"openrouter","persona":"typescript","sessionId":"efec6cfb-7347-4170-8757-00ec3aea432e","tokensIn":60772,"tokensOut":8511,"tokensTotal":69283,"turns":6,"toolCalls":7,"failedToolCalls":0,"timestamp":"2026-07-31T16:07:35.155Z"} -->