← Creature Collection results

Creature Collection

Gemma 4 31b · basic

Initial view of Creature Collection

Reviews & generation details

Reviews

Human review · Jul 17, 2026 · rubric 1

Historical path-based review. Association with these exact bytes is unverified.

Visual design
2 / 5
UX / feel
2 / 5
Works
2 / 5
Prompt spirit
2 / 5
Delight
1 / 5

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 36,394 bytes · SHA-256 2efea9712977
<!DOCTYPE html>
<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>AETHERIUM BINDING</title>
    <style>
        :root {
            --bg-dark: #0a0a12;
            --glass: rgba(255, 255, 255, 0.1);
            --glass-border: rgba(255, 255, 255, 0.2);
            --text-main: #e0e0ff;
            --accent: #70a1ff;
            --danger: #ff4757;
            --success: #2ed573;
            --warning: #ffa502;
            --font-main: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
        }

        * { box-sizing: border-box; user-select: none; }
        body, html { 
            margin: 0; padding: 0; width: 100%; height: 100%; 
            background: var(--bg-dark); color: var(--text-main); 
            font-family: var(--font-main); overflow: hidden; 
        }

        #game-container {
            position: relative; width: 100vw; height: 100vh; 
            display: flex; align-items: center; justify-content: center;
        }

        canvas { 
            image-rendering: pixelated; 
            max-width: 100%; max-height: 100%;
            box-shadow: 0 0 50px rgba(0,0,0,0.5);
        }

        /* UI Systems */
        .overlay {
            position: absolute; top: 0; left: 0; width: 100%; height: 100%;
            display: flex; flex-direction: column; align-items: center; justify-content: center;
            pointer-events: none; z-index: 10;
        }

        .modal {
            pointer-events: auto; background: var(--glass);
            backdrop-filter: blur(15px); border: 1px solid var(--glass-border);
            border-radius: 20px; padding: 30px; text-align: center;
            box-shadow: 0 10px 30px rgba(0,0,0,0.8);
            animation: fadeIn 0.3s ease-out;
            max-width: 90%; max-height: 80%; overflow-y: auto;
        }

        @keyframes fadeIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }

        .hidden { display: none !important; }

        .btn {
            background: var(--accent); color: white; border: none;
            padding: 12px 24px; margin: 10px; border-radius: 8px;
            cursor: pointer; font-weight: bold; transition: 0.2s;
            text-transform: uppercase; letter-spacing: 1px;
        }
        .btn:hover { filter: brightness(1.2); transform: translateY(-2px); }
        .btn:active { transform: translateY(0); }

        /* Battle UI */
        #battle-ui {
            position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%);
            width: 90%; max-width: 800px; display: grid;
            grid-template-columns: 1fr 1fr; gap: 20px;
            pointer-events: auto;
        }

        .battle-menu {
            background: var(--glass); backdrop-filter: blur(10px);
            border: 2px solid var(--glass-border); border-radius: 15px;
            padding: 15px; display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
        }

        .stat-pill {
            background: rgba(0,0,0,0.4); padding: 5px 15px; border-radius: 20px;
            font-size: 0.9em; border: 1px solid var(--glass-border);
        }

        .hp-bar-container {
            width: 100%; height: 12px; background: #333; border-radius: 6px; overflow: hidden;
            margin: 5px 0; border: 1px solid #000;
        }
        .hp-bar-fill {
            height: 100%; background: var(--success); width: 100%;
            transition: width 0.5s ease-out;
        }

        .floating-text {
            position: absolute; color: white; font-weight: bold;
            pointer-events: none; animation: floatUp 1s ease-out forwards;
            text-shadow: 2px 2px 0 #000;
        }
        @keyframes floatUp { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-50px); } }

        .story-flash {
            position: absolute; top: 0; left: 0; width: 100%; height: 100%;
            background: rgba(0,0,0,0.7); display: flex; align-items: center;
            justify-content: center; z-index: 100; pointer-events: auto;
            transition: opacity 0.5s;
        }

        /* Inventory/Team Grids */
        .grid-list {
            display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
            gap: 10px; margin: 20px 0;
        }
        .grid-item {
            background: rgba(0,0,0,0.3); border: 1px solid var(--glass-border);
            padding: 10px; border-radius: 10px; cursor: pointer; transition: 0.2s;
        }
        .grid-item:hover { background: var(--glass); }

        /* Touch Controls */
        #touch-controls {
            position: absolute; bottom: 20px; left: 20px;
            display: grid; grid-template-columns: repeat(3, 50px); gap: 10px;
            pointer-events: auto;
        }
        .touch-btn {
            width: 50px; height: 50px; background: var(--glass);
            border: 1px solid var(--glass-border); border-radius: 50%;
            color: white; display: flex; align-items: center; justify-content: center;
            font-weight: bold; cursor: pointer;
        }

        #mute-toggle {
            position: absolute; top: 20px; right: 20px; z-index: 100;
            pointer-events: auto; background: var(--glass); border: none;
            color: white; padding: 5px 10px; border-radius: 5px; cursor: pointer;
        }
    </style>
</head>
<body>

<div id="game-container">
    <canvas id="gameCanvas"></canvas>
    
    <button id="mute-toggle">Audio: ON</button>

    <!-- Title Screen -->
    <div id="title-screen" class="overlay">
        <div class="modal">
            <h1 style="font-size: 3em; margin-bottom: 10px; color: var(--accent);">AETHERIUM</h1>
            <p style="margin-bottom: 30px; font-style: italic;">Bind the fragments of the shattered void.</p>
            <button class="btn" onclick="game.startNewGame()">New Binding</button>
            <button class="btn" onclick="game.continueGame()">Continue</button>
        </div>
    </div>

    <!-- Story/Dialogue Overlay -->
    <div id="story-overlay" class="story-flash hidden">
        <div class="modal" style="max-width: 600px;">
            <p id="story-text" style="font-size: 1.2em; line-height: 1.6;"></p>
            <button class="btn" onclick="game.closeStory()">Proceed</button>
        </div>
    </div>

    <!-- Battle UI -->
    <div id="battle-screen" class="overlay hidden">
        <!-- Entities rendered on canvas -->
        <div id="battle-ui">
            <div class="battle-menu" id="battle-actions">
                <button class="btn" onclick="game.battle.handleAction('attack')">Strike</button>
                <button class="btn" onclick="game.battle.handleAction('special')">Aether</button>
                <button class="btn" onclick="game.battle.handleAction('item')">Vessel</button>
                <button class="btn" onclick="game.battle.handleAction('switch')">Switch</button>
            </div>
            <div class="battle-menu" id="ability-selection" style="display:none;">
                <!-- Ability buttons injected here -->
            </div>
            <div class="battle-log" style="background: var(--glass); padding: 15px; border-radius: 15px; border: 1px solid var(--glass-border); font-size: 0.9em;">
                <div id="battle-msg">A wild creature emerges!</div>
            </div>
        </div>
    </div>

    <!-- Menu System -->
    <div id="menu-overlay" class="overlay hidden">
        <div class="modal" id="menu-modal">
            <!-- Dynamic content -->
        </div>
    </div>

    <!-- Overworld Controls -->
    <div id="touch-controls" class="hidden">
        <div></div><div class="touch-btn" onmousedown="game.input.setKey('KeyW', true)" onmouseup="game.input.setKey('KeyW', false)">↑</div><div></div>
        <div class="touch-btn" onmousedown="game.input.setKey('KeyA', true)" onmouseup="game.input.setKey('KeyA', false)">←</div>
        <div class="touch-btn" onmousedown="game.input.setKey('KeyS', true)" onmouseup="game.input.setKey('KeyS', false)">↓</div>
        <div class="touch-btn" onmousedown="game.input.setKey('KeyD', true)" onmouseup="game.input.setKey('KeyD', false)">→</div>
    </div>
</div>

<script>
/**
 * GAME DATA & CONSTANTS
 * Theme: Aetherium - Floating islands of crystallized energy.
 * Creatures: "Essences".
 */

const TYPES = {
    SOLAR: { name: 'Solar', color: '#ff9f43' },   // A
    LUNAR: { name: 'Lunar', color: '#54a0ff' },   // B
    VAPOR: { name: 'Vapor', color: '#00d2d3' },   // C
    CORE: { name: 'Core', color: '#ee5253' },     // D
    VOID: { name: 'Void', color: '#5f27cd' },     // E
    PRISM: { name: 'Prism', color: '#ff9ff3' },   // F
    STASIS: { name: 'Stasis', color: '#c8d6e5' }  // G
};

const TYPE_CHART = {
    // Solar > Lunar > Vapor > Solar
    'Solar': { 'Lunar': 1.5, 'Vapor': 0.5, 'Core': 0.5, 'Void': 1.0, 'Prism': 1.0, 'Stasis': 1.0 },
    'Lunar': { 'Vapor': 1.5, 'Solar': 0.5, 'Core': 0.5, 'Void': 1.0, 'Prism': 1.0, 'Stasis': 1.0 },
    'Vapor': { 'Solar': 1.5, 'Lunar': 0.5, 'Core': 0.5, 'Void': 1.0, 'Prism': 1.0, 'Stasis': 1.0 },
    // Core > Solar & Vapor
    'Core': { 'Solar': 1.5, 'Vapor': 1.5, 'Lunar': 1.0, 'Void': 0.5, 'Prism': 1.0, 'Stasis': 1.0 },
    // Void > Core & Lunar
    'Void': { 'Core': 1.5, 'Lunar': 1.5, 'Solar': 1.0, 'Vapor': 1.0, 'Prism': 1.0, 'Stasis': 1.0 },
    // Prism beats all slightly (1.2x)
    'Prism': { 'Solar': 1.2, 'Lunar': 1.2, 'Vapor': 1.2, 'Core': 1.2, 'Void': 1.2, 'Stasis': 2.0 },
    // Stasis resists everything, weak to Prism
    'Stasis': { 'Solar': 0.5, 'Lunar': 0.5, 'Vapor': 0.5, 'Core': 0.5, 'Void': 0.5, 'Prism': 0.5, 'Stasis': 1.0 }
};

const ABILITIES = {
    'Singe': { power: 40, accuracy: 95, type: 'Solar', cost: 10, effect: 'burn', desc: 'Heat pulse. Chance to burn.' },
    'Tide': { power: 40, accuracy: 95, type: 'Lunar', cost: 10, effect: 'none', desc: 'Watery surge.' },
    'Mist': { power: 40, accuracy: 95, type: 'Vapor', cost: 10, effect: 'frost', desc: 'Chilling fog. Chance to freeze.' },
    'Crush': { power: 60, accuracy: 80, type: 'Core', cost: 15, effect: 'none', desc: 'Heavy impact.' },
    'Null': { power: 60, accuracy: 80, type: 'Void', cost: 15, effect: 'shock', desc: 'Void blast. Chance to shock.' },
    'Refract': { power: 50, accuracy: 100, type: 'Prism', cost: 12, effect: 'none', desc: 'Prismatic beam.' },
    'Sustain': { power: 0, accuracy: 100, type: 'Stasis', cost: 15, effect: 'regen', desc: 'Restore HP over time.' },
    'Flare': { power: 110, accuracy: 70, type: 'Solar', cost: 30, effect: 'burn', desc: 'Explosive heat.' },
    'Eclipse': { power: 110, accuracy: 70, type: 'Lunar', cost: 30, effect: 'none', desc: 'Dark wave.' },
    'Cyclone': { power: 110, accuracy: 70, type: 'Vapor', cost: 30, effect: 'frost', desc: 'Raging storm.' },
    'Quake': { power: 120, accuracy: 60, type: 'Core', cost: 40, effect: 'none', desc: 'Shattering strike.' },
    'Oblivion': { power: 120, accuracy: 60, type: 'Void', cost: 40, effect: 'shock', desc: 'Total erasure.' },
    'Spectrum': { power: 100, accuracy: 90, type: 'Prism', cost: 30, effect: 'none', desc: 'All-color burst.' },
    'Aegis': { power: 0, accuracy: 100, type: 'Stasis', cost: 20, effect: 'barrier', desc: 'Crystal shield.' },
    'Searing Ray': { power: 70, accuracy: 90, type: 'Solar', cost: 15, effect: 'none', desc: 'Piercing light.' },
    'Moonbeam': { power: 70, accuracy: 90, type: 'Lunar', cost: 15, effect: 'none', desc: 'Gentle but firm.' },
    'Steam Vent': { power: 70, accuracy: 90, type: 'Vapor', cost: 15, effect: 'burn', desc: 'Hot steam.' },
    'Tectonic': { power: 80, accuracy: 75, type: 'Core', cost: 20, effect: 'none', desc: 'Ground shift.' },
    'Singularity': { power: 80, accuracy: 75, type: 'Void', cost: 20, effect: 'none', desc: 'Gravity well.' },
    'Prism Wave': { power: 80, accuracy: 85, type: 'Prism', cost: 20, effect: 'none', desc: 'Rainbow wave.' },
    'Stillness': { power: 0, accuracy: 100, type: 'Stasis', cost: 10, effect: 'frost', desc: 'Freeze time.' },
    'Solar Wind': { power: 50, accuracy: 100, type: 'Solar', cost: 5, effect: 'none', desc: 'Quick breeze.' },
    'Lunar Drift': { power: 50, accuracy: 100, type: 'Lunar', cost: 5, effect: 'none', desc: 'Fluid motion.' },
    'Vapor Step': { power: 50, accuracy: 100, type: 'Vapor', cost: 5, effect: 'none', desc: 'Ghostly shift.' },
    'Iron Skin': { power: 0, accuracy: 100, type: 'Core', cost: 15, effect: 'barrier', desc: 'Harden surface.' },
    'Void Grip': { power: 60, accuracy: 85, type: 'Void', cost: 15, effect: 'none', desc: 'Tearing force.' },
    'Light Shell': { power: 0, accuracy: 100, type: 'Prism', cost: 15, effect: 'barrier', desc: 'Reflective skin.' },
    'Zenith': { power: 150, accuracy: 50, type: 'Solar', cost: 50, effect: 'burn', desc: 'Highest peak.' },
    'Nadir': { power: 150, accuracy: 50, type: 'Lunar', cost: 50, effect: 'none', desc: 'Deepest valley.' },
    'Vortex': { power: 150, accuracy: 50, type: 'Vapor', cost: 50, effect: 'frost', desc: 'Sucking wind.' },
    'Cataclysm': { power: 160, accuracy: 40, type: 'Core', cost: 60, effect: 'none', desc: 'World ender.' },
    'Entropy': { power: 160, accuracy: 40, type: 'Void', cost: 60, effect: 'shock', desc: 'Energy decay.' },
    'Radiance': { power: 130, accuracy: 80, type: 'Prism', cost: 40, effect: 'none', desc: 'Pure light.' },
    'Eternal': { power: 0, accuracy: 100, type: 'Stasis', cost: 30, effect: 'regen', desc: 'Infinite life.' },
    'Spark': { power: 30, accuracy: 100, type: 'Solar', cost: 5, effect: 'none', desc: 'Tiny spark.' },
    'Dew': { power: 30, accuracy: 100, type: 'Lunar', cost: 5, effect: 'none', desc: 'Morning dew.' },
    'Gale': { power: 30, accuracy: 100, type: 'Vapor', cost: 5, effect: 'none', desc: 'Light wind.' },
    'Silt': { power: 30, accuracy: 100, type: 'Core', cost: 5, effect: 'none', desc: 'Dirt spray.' },
    'Echo': { power: 30, accuracy: 100, type: 'Void', cost: 5, effect: 'none', desc: 'Void echo.' },
    'Glint': { power: 30, accuracy: 100, type: 'Prism', cost: 5, effect: 'none', desc: 'Quick glint.' }
};

const ESSENCE_DATA = [
    { id: 0, name: 'Pyris', type: 'Solar', hp: 45, atk: 55, def: 40, spd: 60, lore: 'A small ember with a fiery spirit.', learns: [0, 14, 7, 27], evolves: { level: 20, into: 18 } },
    { id: 1, name: 'Aquilo', type: 'Lunar', hp: 50, atk: 45, def: 50, spd: 50, lore: 'Fluid essence resembling a floating pearl.', learns: [1, 15, 8, 28], evolves: { level: 20, into: 19 } },
    { id: 2, name: 'Vesper', type: 'Vapor', hp: 40, atk: 50, def: 30, spd: 70, lore: 'A whispering cloud of silver mist.', learns: [2, 16, 9, 29], evolves: { level: 20, into: 20 } },
    { id: 3, name: 'Terran', type: 'Core', hp: 60, atk: 65, def: 60, spd: 30, lore: 'A floating jagged piece of obsidian.', learns: [3, 17, 10, 30], evolves: { level: 20, into: 21 } },
    { id: 4, name: 'Nyx', type: 'Void', hp: 40, atk: 60, def: 40, spd: 60, lore: 'A shadow that defies the light.', learns: [4, 18, 11, 31], evolves: { level: 20, into: 22 } },
    { id: 5, name: 'Lumina', type: 'Prism', hp: 45, atk: 45, def: 45, spd: 65, lore: 'A crystalline prism that refracts all colors.', learns: [5, 19, 12, 32], evolves: { level: 20, into: 23 } },
    { id: 6, name: 'Sola', type: 'Solar', hp: 40, atk: 60, def: 30, spd: 70, lore: 'A floating ray of sunlight.', learns: [0, 14, 22, 7], evolves: { level: 20, into: 18 } },
    { id: 7, name: 'Luna', type: 'Lunar', hp: 55, atk: 40, def: 55, spd: 45, lore: 'A crescent-shaped water wisp.', learns: [1, 15, 23, 8], evolves: { level: 20, into: 19 } },
    { id: 8, name: 'Vapo', type: 'Vapor', hp: 35, atk: 55, def: 35, spd: 75, lore: 'A swirling air vortex.', learns: [2, 16, 24, 9], evolves: { level: 20, into: 20 } },
    { id: 9, name: 'Coru', type: 'Core', hp: 70, atk: 50, def: 70, spd: 25, lore: 'A heavy metallic sphere.', learns: [3, 17, 25, 10], evolves: { level: 20, into: 21 } },
    { id: 10, name: 'Voida', type: 'Void', hp: 45, atk: 55, def: 45, spd: 55, lore: 'A fragment of a dead star.', learns: [4, 18, 26, 11], evolves: { level: 20, into: 22 } },
    { id: 11, name: 'Prismi', type: 'Prism', hp: 40, atk: 50, def: 40, spd: 60, lore: 'A sparkling diamond shard.', learns: [5, 19, 27, 12], evolves: { level: 20, into: 23 } },
    { id: 12, name: 'Stasi', type: 'Stasis', hp: 80, atk: 30, def: 80, spd: 20, lore: 'A frozen moment in time.', learns: [6, 13, 30, 33], evolves: null },
    { id: 13, name: 'Ignis', type: 'Solar', hp: 50, atk: 70, def: 40, spd: 50, lore: 'A living bonfire.', learns: [0, 14, 7, 27], evolves: { level: 20, into: 18 } },
    { id: 14, name: 'Glacia', type: 'Lunar', hp: 50, atk: 70, def: 40, spd: 50, lore: 'An ice spire floating in air.', learns: [1, 15, 8, 28], evolves: { level: 20, into: 19 } },
    { id: 15, name: 'Zephyr', type: 'Vapor', hp: 40, atk: 70, def: 30, spd: 70, lore: 'A whirlwind of shards.', learns: [2, 16, 9, 29], evolves: { level: 20, into: 20 } },
    { id: 16, name: 'Groma', type: 'Core', hp: 70, atk: 60, def: 70, spd: 30, lore: 'A mountain-sized pebble.', learns: [3, 17, 10, 30], evolves: { level: 20, into: 21 } },
    { id: 17, name: 'Umbra', type: 'Void', hp: 50, atk: 60, def: 50, spd: 50, lore: 'The echo of a scream.', learns: [4, 18, 11, 31], evolves: { level: 20, into: 22 } },
    // Transformed / Evolved
    { id: 18, name: 'Pyrosurge', type: 'Solar', hp: 70, atk: 90, def: 60, spd: 80, lore: 'A raging sun-beast.', learns: [27, 14, 7, 27], evolves: null },
    { id: 19, name: 'Aquastorm', type: 'Lunar', hp: 80, atk: 80, def: 70, spd: 70, lore: 'The oceanic sovereign.', learns: [28, 15, 8, 28], evolves: null },
    { id: 20, name: 'Vaporwind', type: 'Vapor', hp: 60, atk: 90, def: 50, spd: 100, lore: 'A storm that never ends.', learns: [29, 16, 9, 29], evolves: null },
    { id: 21, name: 'Corite Titan', type: 'Core', hp: 100, atk: 100, def: 100, spd: 40, lore: 'A fortress of living rock.', learns: [30, 17, 10, 30], evolves: null },
    { id: 22, name: 'Void Reaver', type: 'Void', hp: 70, atk: 110, def: 60, spd: 90, lore: 'A reaper of aether.', learns: [31, 18, 11, 31], evolves: null },
    { id: 23, name: 'Prism Lord', type: 'Prism', hp: 75, atk: 85, def: 75, spd: 85, lore: 'Master of all spectrums.', learns: [32, 19, 12, 32], evolves: null },
    // More fillers to reach 27
    { id: 24, name: 'Stalactox', type: 'Stasis', hp: 90, atk: 40, def: 90, spd: 20, lore: 'A petrified giant.', learns: [6, 13, 30, 33], evolves: null },
    { id: 25, name: 'Flareonix', type: 'Solar', hp: 65, atk: 85, def: 55, spd: 75, lore: 'Bright as a midday star.', learns: [0, 14, 7, 27], evolves: null },
    { id: 26, name: 'Tidewave', type: 'Lunar', hp: 65, atk: 85, def: 55, spd: 75, lore: 'A rolling lunar tide.', learns: [1, 15, 8, 28], evolves: null },
    // The 27th
    { id: 26, name: 'Apex', type: 'Prism', hp: 100, atk: 100, def: 100, spd: 100, lore: 'The ultimate binding.', learns: [32, 5, 19, 12], evolves: null },
];
// Fix IDs for the last few to be unique
ESSENCE_DATA[24].id = 24;
ESSENCE_DATA[25].id = 25;
ESSENCE_DATA[26].id = 26;

const ZONES = [
    { name: 'Luminous Plains', grad: ['#5eead4', '#ace1e1'], encounterRate: 0.1, boss: 'Sola Prime', color: '#70a1ff' },
    { name: 'Obsidian Spires', grad: ['#4b5563', '#1f2937'], encounterRate: 0.15, boss: 'Coru Titan', color: '#ee5253' },
    { name: 'Azure Depths', grad: ['#0ea5e9', '#0369a1'], encounterRate: 0.15, boss: 'Tidewave', color: '#54a0ff' },
    { name: 'Void Hollows', grad: ['#2e1065', '#020617'], encounterRate: 0.2, boss: 'Void Reaver', color: '#5f27cd' },
    { name: 'Prism Garden', grad: ['#fbcfe8', '#db2777'], encounterRate: 0.2, boss: 'Prism Lord', color: '#ff9ff3' },
    { name: 'The Eternal Core', grad: ['#fef3c7', '#b45309'], encounterRate: 0.25, boss: 'Aether Apex', color: '#facc15' },
];

const ITEMS = {
    BIND_SMALL: { name: 'Glass Vessel', effect: 'capture', quality: 0.4 },
    BIND_MED: { name: 'Quartz Vessel', effect: 'capture', quality: 0.7 },
    BIND_LARGE: { name: 'Diamond Vessel', effect: 'capture', quality: 0.95 },
    HEAL_S: { name: 'Aether Dust', effect: 'heal', value: 50 },
    HEAL_M: { name: 'Aether Shard', effect: 'heal', value: 150 },
    CATALYST: { name: 'Void Catalyst', effect: 'evolve' },
};

/**
 * CORE GAME ENGINE
 */

class Game {
    constructor() {
        this.canvas = document.getElementById('gameCanvas');
        this.ctx = this.canvas.getContext('2d');
        this.width = 800;
        this.height = 600;
        this.canvas.width = this.width;
        this.canvas.height = this.height;

        this.state = 'TITLE'; // TITLE, OVERWORLD, BATTLE, MENU, STORY
        this.player = {
            x: 400, y: 300,
            zone: 0,
            party: [],
            inventory: {
                BIND_SMALL: 5, BIND_MED: 0, BIND_LARGE: 0,
                HEAL_S: 5, HEAL_M: 0, CATALYST: 0
            },
            collected: [],
            anchorsDefeated: 0
        };

        this.input = {
            keys: {},
            setKey(k, v) { this.keys[k] = v; }
        };

        this.audio = {
            ctx: null,
            muted: false,
            init() {
                this.ctx = new (window.AudioContext || window.webkitAudioContext)();
            },
            beep(freq, dur = 0.1, vol = 0.1) {
                if (this.muted || !this.ctx) return;
                const osc = this.ctx.createOscillator();
                const gain = this.ctx.createGain();
                osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
                gain.gain.setValueAtTime(vol, this.ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + dur);
                osc.connect(gain);
                gain.connect(this.ctx.destination);
                osc.start();
                osc.stop(this.ctx.currentTime + dur);
            }
        };

        window.addEventListener('keydown', e => this.input.setKey(e.code, true));
        window.addEventListener('keyup', e => this.input.setKey(e.code, false));
        document.getElementById('mute-toggle').onclick = () => {
            this.audio.muted = !this.audio.muted;
            document.getElementById('mute-toggle').innerText = `Audio: ${this.audio.muted ? 'OFF' : 'ON'}`;
        };

        this.loop();
    }

    startNewGame() {
        this.audio.init();
        this.state = 'STORY';
        this.showStory("Welcome to Aetherium. You are a Binder, tasked with collecting the fragmented Essences to stabilize the Void.");
        this.setupStarter();
        document.getElementById('title-screen').classList.add('hidden');
        document.getElementById('touch-controls').classList.remove('hidden');
    }

    setupStarter() {
        // Simple starter choice logic
        const starters = [0, 1, 2];
        const choice = 0; // Default Pyris
        const base = ESSENCE_DATA[choice];
        this.player.party.push(this.createEssence(base, 5));
    }

    continueGame() {
        const saved = localStorage.getItem('aetherium_save');
        if (saved) {
            this.player = JSON.parse(saved);
            this.state = 'OVERWORLD';
            document.getElementById('title-screen').classList.add('hidden');
        } else {
            alert("No saved binding found.");
        }
    }

    createEssence(data, level) {
        const e = { ...data, level, curHp: data.hp, maxHp: data.hp };
        // Scale stats
        e.atk += (level - 1) * 2;
        e.def += (level - 1) * 2;
        e.hp += (level - 1) * 5;
        e.curHp = e.hp;
        e.maxHp = e.hp;
        return e;
    }

    showStory(text) {
        this.state = 'STORY';
        document.getElementById('story-overlay').classList.remove('hidden');
        document.getElementById('story-text').innerText = text;
    }

    closeStory() {
        document.getElementById('story-overlay').classList.add('hidden');
        this.state = 'OVERWORLD';
    }

    save() {
        localStorage.setItem('aetherium_save', JSON.stringify(this.player));
        this.audio.beep(440, 0.2);
    }

    loop() {
        this.update();
        this.draw();
        requestAnimationFrame(() => this.loop());
    }

    update() {
        if (this.state === 'OVERWORLD') {
            const speed = 4;
            let moved = false;
            if (this.input.keys['KeyW'] || this.input.keys['ArrowUp']) { this.player.y -= speed; moved = true; }
            if (this.input.keys['KeyS'] || this.input.keys['ArrowDown']) { this.player.y += speed; moved = true; }
            if (this.input.keys['KeyA'] || this.input.keys['ArrowLeft']) { this.player.x -= speed; moved = true; }
            if (this.input.keys['KeyD'] || this.input.keys['ArrowRight']) { this.player.x += speed; moved = true; }

            // Boundaries
            this.player.x = Math.max(0, Math.min(this.width, this.player.x));
            this.player.y = Math.max(0, Math.min(this.height, this.player.y));

            if (moved) {
                if (Math.random() < ZONES[this.player.zone].encounterRate * 0.05) {
                    this.initBattle();
                }
            }
            
            // Zone transitions (simplified)
            if (this.player.x > this.width - 5 && this.player.zone < 5) {
                this.player.zone++;
                this.player.x = 10;
                this.showStory(`You have entered the ${ZONES[this.player.zone].name}. The air feels different here.`);
            }
        }
    }

    draw() {
        const ctx = this.ctx;
        ctx.clearRect(0, 0, this.width, this.height);

        if (this.state === 'OVERWORLD' || this.state === 'STORY') {
            const zone = ZONES[this.player.zone];
            const grad = ctx.createLinearGradient(0, 0, 0, this.height);
            grad.addColorStop(0, zone.grad[0]);
            grad.addColorStop(1, zone.grad[1]);
            ctx.fillStyle = grad;
            ctx.fillRect(0, 0, this.width, this.height);

            // Grid
            ctx.strokeStyle = 'rgba(255,255,255,0.1)';
            ctx.lineWidth = 1;
            for(let i=0; i<this.width; i+=50) {
                ctx.beginPath(); ctx.moveTo(i,0); ctx.lineTo(i, this.height); ctx.stroke();
            }
            for(let i=0; i<this.height; i+=50) {
                ctx.beginPath(); ctx.moveTo(0,i); ctx.lineTo(this.width, i); ctx.stroke();
            }

            // Player
            ctx.fillStyle = 'white';
            ctx.beginPath();
            ctx.arc(this.player.x, this.player.y, 10, 0, Math.PI*2);
            ctx.fill();
            ctx.shadowBlur = 15; ctx.shadowColor = 'white';
            ctx.stroke(); ctx.shadowBlur = 0;
        }

        if (this.state === 'BATTLE') {
            this.battle.draw();
        }
    }

    initBattle() {
        this.state = 'BATTLE';
        this.battle.start();
        document.getElementById('battle-screen').classList.remove('hidden');
    }

    endBattle(victory) {
        this.state = 'OVERWORLD';
        document.getElementById('battle-screen').classList.add('hidden');
        if (victory) this.audio.beep(660, 0.3);
    }
}

class BattleSystem {
    constructor(game) {
        this.game = game;
        this.enemies = [];
        this.activePlayerIdx = 0;
        this.turnQueue = [];
        this.currentTurnIdx = 0;
        this.isProcessing = false;
    }

    start() {
        const zone = ZONES[this.game.player.zone];
        const enemyCount = 1 + Math.floor(Math.random() * 2);
        this.enemies = [];
        for (let i = 0; i < enemyCount; i++) {
            const species = ESSENCE_DATA[Math.floor(Math.random() * 18)];
            const lvl = 5 + (this.game.player.zone * 5) + Math.floor(Math.random() * 3);
            this.enemies.push(this.game.createEssence(species, lvl));
        }
        this.activePlayerIdx = 0;
        this.setupTurnOrder();
        this.log(`A wild ${this.enemies[0].name} appeared!`);
    }

    setupTurnOrder() {
        this.turnQueue = [];
        this.game.player.party.forEach((p, idx) => this.turnQueue.push({ type: 'player', id: idx, spd: p.spd }));
        this.enemies.forEach((e, idx) => this.turnQueue.push({ type: 'enemy', id: idx, spd: e.spd }));
        this.turnQueue.sort((a, b) => b.spd - a.spd);
        this.currentTurnIdx = 0;
        this.processTurn();
    }

    processTurn() {
        this.isProcessing = false;
        const turn = this.turnQueue[this.currentTurnIdx];
        if (turn.type === 'enemy') {
            setTimeout(() => this.enemyTurn(turn.id), 1000);
        } else {
            this.game.state = 'BATTLE';
            this.game.battle.activeTurn = turn.id;
            this.log(`Turn: ${this.game.player.party[turn.id].name}`);
        }
    }

    get activeTurn() { return this.game.battle.activeTurn; }

    enemyTurn(enemyIdx) {
        const enemy = this.enemies[enemyIdx];
        const targetIdx = Math.floor(Math.random() * this.game.player.party.length);
        const target = this.game.player.party[targetIdx];
        
        const moveIdx = Math.floor(Math.random() * 4);
        const moveName = enemy.learns[moveIdx];
        const move = ABILITIES[Object.keys(ABILITIES)[moveName] || 'Singe']; // Simplified
        
        this.log(`${enemy.name} uses ${moveName}!`);
        this.resolveAttack(enemy, target, moveName);
    }

    handleAction(action) {
        if (this.isProcessing) return;

        if (action === 'attack') {
            const p = this.game.player.party[this.activeTurn];
            const moves = p.learns.map(id => Object.keys(ABILITIES)[id]);
            this.showAbilityMenu(moves);
        } else if (action === 'item') {
            this.showItemMenu();
        } else if (action === 'switch') {
            this.showSwitchMenu();
        }
    }

    showAbilityMenu(moves) {
        const menu = document.getElementById('ability-selection');
        const actions = document.getElementById('battle-actions');
        actions.style.display = 'none';
        menu.style.display = 'grid';
        menu.innerHTML = '';
        
        moves.forEach(m => {
            const btn = document.createElement('button');
            btn.className = 'btn';
            btn.innerText = m;
            btn.onclick = () => {
                const target = this.enemies[0]; // Simplified to first enemy
                this.resolveAttack(this.game.player.party[this.activeTurn], target, m);
                menu.style.display = 'none';
                actions.style.display = 'grid';
            };
            menu.appendChild(btn);
        });
    }

    showItemMenu() {
        const menu = document.getElementById('ability-selection');
        const actions = document.getElementById('battle-actions');
        actions.style.display = 'none';
        menu.style.display = 'grid';
        menu.innerHTML = '';

        Object.keys(this.game.player.inventory).forEach(key => {
            const qty = this.game.player.inventory[key];
            if (qty <= 0) return;
            const item = ITEMS[key];
            const btn = document.createElement('button');
            btn.className = 'btn';
            btn.innerText = `${item.name} (${qty})`;
            btn.onclick = () => {
                this.useItem(key);
                menu.style.display = 'none';
                actions.style.display = 'grid';
            };
            menu.appendChild(btn);
        });
    }

    useItem(key) {
        const item = ITEMS[key];
        if (item.effect === 'capture') {
            const target = this.enemies[0];
            const chance = (1 - target.curHp/target.maxHp) * item.quality;
            if (Math.random() < chance) {
                this.log(`Success! ${target.name} was bound!`);
                this.game.player.party.push(target);
                this.game.player.collected.push(target.id);
                this.game.player.inventory[key]--;
                this.checkVictory();
            } else {
                this.log(`The ${target.name} broke free!`);
                this.game.player.inventory[key]--;
            }
        } else if (item.effect === 'heal') {
            const p = this.game.player.party[this.activeTurn];
            p.curHp = Math.min(p.maxHp, p.curHp + item.value);
            this.log(`${p.name} healed!`);
            this.game.player.inventory[key]--;
        }
    }

    showSwitchMenu() {
        const menu = document.getElementById('ability-selection');
        const actions = document.getElementById('battle-actions');
        actions.style.display = 'none';
        menu.style.display = 'grid';
        menu.innerHTML = '';

        this.game.player.party.forEach((p, idx) => {
            const btn = document.createElement('button');
            btn.className = 'btn';
            btn.innerText = `${p.name} (HP: ${p.curHp})`;
            btn.onclick = () => {
                this.activeTurn = idx;
                this.log(`Switched to ${p.name}!`);
                menu.style.display = 'none';
                actions.style.display = 'grid';
            };
            menu.appendChild(btn);
        });
    }

    resolveAttack(attacker, defender, moveId) {
        this.isProcessing = true;
        const move = ABILITIES[moveId] || ABILITIES['Singe'];
        
        // Damage Formula: (0.4 * Level * ATK / DEF * Multiplier) + random
        const mult = TYPE_CHART[attacker.type][defender.type] || 1.0;
        const stab = (move.type === attacker.type) ? 1.25 : 1.0;
        let damage = Math.floor((0.4 * attacker.level * attacker.atk / defender.def * mult * stab) + Math.random() * 5);
        
        if (Math.random() < 0.1) {
            damage *= 2;
            this.log("CRITICAL HIT!");
        }

        defender.curHp -= damage;
        this.log(`${attacker.name} deals ${damage} damage!`);
        this.game.audio.beep(200, 0.1);

        if (defender.curHp <= 0) {
            defender.curHp = 0;
            this.log(`${defender.name} fainted!`);
        }

        setTimeout(() => {
            this.nextTurn();
        }, 1500);
    }

    nextTurn() {
        this.currentTurnIdx++;
        if (this.currentTurnIdx >= this.turnQueue.length) {
            this.currentTurnIdx = 0;
            this.setupTurnOrder();
        } else {
            this.processTurn();
        }
    }

    checkVictory() {
        if (this.enemies.every(e => e.curHp <= 0)) {
            this.log("Battle won!");
            setTimeout(() => this.game.endBattle(true), 2000);
        }
    }

    log(msg) {
        document.getElementById('battle-msg').innerText = msg;
    }

    draw() {
        const ctx = this.game.ctx;
        // Background
        ctx.fillStyle = '#1a1a2e';
        ctx.fillRect(0, 0, this.game.width, this.game.height);

        // Simple Render of Entities
        this.game.player.party.forEach((p, i) => {
            ctx.fillStyle = TYPES[p.type].color;
            ctx.beginPath();
            ctx.arc(200, 400 - (i * 40), 20, 0, Math.PI*2);
            ctx.fill();
            
            ctx.fillStyle = 'white';
            ctx.fillText(`${p.name} L${p.level}`, 230, 405 - (i * 40));
            
            // HP Bar
            ctx.fillStyle = '#333';
            ctx.fillRect(280, 400 - (i * 40), 100, 10);
            ctx.fillStyle = 'lime';
            ctx.fillRect(280, 400 - (i * 40), (p.curHp / p.maxHp) * 100, 10);
        });

        this.enemies.forEach((e, i) => {
            ctx.fillStyle = TYPES[e.type].color;
            ctx.beginPath();
            ctx.arc(600, 200 + (i * 60), 30, 0, Math.PI*2);
            ctx.fill();
            
            ctx.fillStyle = 'white';
            ctx.fillText(`${e.name} L${e.level}`, 530, 205 + (i * 60));
            
            ctx.fillStyle = '#333';
            ctx.fillRect(530, 210 + (i * 60), 100, 10);
            ctx.fillStyle = 'lime';
            ctx.fillRect(530, 210 + (i * 60), (e.curHp / e.maxHp) * 100, 10);
        });
    }
}

// Instantiate game and attach battle system
const game = new Game();
game.battle = new BattleSystem(game);

</script>
</body>
</html>
<!-- agent-meta {"model":"gemma-4-31b","provider":"cerebras","persona":"basic","sessionId":"3aa84e90-4d57-4bed-8d2e-c0da2a80a4a5","tokensIn":1337,"tokensOut":12634,"tokensTotal":13971,"turns":1,"toolCalls":0,"failedToolCalls":0,"timestamp":"2026-07-14T21:56:06.212Z"} -->