← Creature Collection results

Creature Collection

Gemma 4 31b · middle

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
1 / 5
UX / feel
2 / 5
Works
1 / 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 42,368 bytes · SHA-256 27bfe6fffd50
<!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>Aetheria: The Shard Bound</title>
    <style>
        :root {
            --bg-deep: #0a0b1e;
            --glass: rgba(255, 255, 255, 0.1);
            --glass-border: rgba(255, 255, 255, 0.2);
            --accent: #00f2ff;
            --text: #e0e6ed;
            --gold: #ffd700;
            --danger: #ff4d4d;
        }

        * { box-sizing: border-box; user-select: none; -webkit-tap-highlight-color: transparent; }
        body, html { 
            margin: 0; padding: 0; width: 100%; height: 100%; 
            overflow: hidden; background: var(--bg-deep); 
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 
            color: var(--text); 
        }

        #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);
        }

        /* Glassmorphism UI */
        .overlay {
            position: absolute; top: 0; left: 0; width: 100%; height: 100%;
            display: flex; flex-direction: column; align-items: center; justify-content: center;
            background: rgba(0,0,0,0.7); backdrop-filter: blur(8px);
            z-index: 100; transition: opacity 0.3s ease;
        }

        .hidden { display: none !important; opacity: 0; pointer-events: none; }

        .panel {
            background: var(--glass);
            border: 1px solid var(--glass-border);
            border-radius: 20px;
            padding: 2rem;
            box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.8);
            text-align: center;
            max-width: 80%;
            animation: slideUp 0.4s ease-out;
        }

        @keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

        button {
            background: var(--glass);
            border: 1px solid var(--accent);
            color: var(--text);
            padding: 12px 24px;
            margin: 10px;
            border-radius: 10px;
            cursor: pointer;
            font-size: 1rem;
            transition: all 0.2s;
            text-transform: uppercase;
            letter-spacing: 1px;
        }

        button:hover { background: var(--accent); color: var(--bg-deep); box-shadow: 0 0 15px var(--accent); }

        #dialogue-box {
            position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%);
            width: 90%; max-width: 700px;
            background: rgba(10, 11, 30, 0.85);
            border: 2px solid var(--accent);
            border-radius: 15px;
            padding: 20px;
            z-index: 90;
            cursor: pointer;
            display: none;
        }

        #hud {
            position: absolute; top: 20px; left: 20px;
            pointer-events: none;
            z-index: 80;
            display: flex; gap: 10px;
        }

        .hud-item {
            background: var(--glass);
            padding: 8px 15px;
            border-radius: 10px;
            border: 1px solid var(--glass-border);
            font-size: 0.9rem;
        }

        /* Battle UI */
        #battle-ui {
            position: absolute; bottom: 0; left: 0; width: 100%;
            height: 40%; background: linear-gradient(transparent, var(--bg-deep));
            display: none; grid-template-columns: 1fr 1fr;
            padding: 20px; z-index: 110;
        }

        .battle-menu {
            display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
        }

        .stat-bar-container {
            width: 200px; height: 12px; background: #333;
            border-radius: 6px; overflow: hidden; margin: 5px 0;
        }
        .stat-bar-fill { height: 100%; width: 100%; transition: width 0.5s ease; }
        .hp-fill { background: #4caf50; }
        .exp-fill { background: #2196f3; }

        #controls {
            position: absolute; bottom: 30px; right: 30px;
            display: grid; grid-template-columns: repeat(3, 60px); gap: 10px;
            z-index: 80;
        }
        .ctrl-btn {
            width: 60px; height: 60px; background: var(--glass);
            border: 1px solid var(--glass-border); border-radius: 50%;
            display: flex; align-items: center; justify-content: center;
            font-weight: bold; cursor: pointer;
        }

        .type-icon {
            display: inline-block; width: 12px; height: 12px; border-radius: 50%; margin-right: 5px;
        }
    </style>
</head>
<body>

<div id="game-container">
    <canvas id="mainCanvas"></canvas>
    
    <div id="hud">
        <div class="hud-item" id="hud-zone">Zone: Echo Plains</div>
        <div class="hud-item" id="hud-party">Creatures: 0/6</div>
    </div>

    <div id="controls">
        <div></div><div class="ctrl-btn" id="btn-up">W</div><div></div>
        <div class="ctrl-btn" id="btn-left">A</div><div class="ctrl-btn" id="btn-down">S</div><div class="ctrl-btn" id="btn-right">D</div>
    </div>

    <div id="dialogue-box">
        <div id="dialogue-text">Welcome to Aetheria...</div>
        <div style="font-size: 0.7rem; text-align: right; margin-top: 10px; opacity: 0.6;">Click to continue...</div>
    </div>

    <div id="battle-ui">
        <div id="battle-stats"></div>
        <div class="battle-menu" id="battle-actions"></div>
    </div>

    <!-- Screens -->
    <div id="screen-title" class="overlay">
        <div class="panel">
            <h1 style="color: var(--accent); font-size: 3rem; margin-bottom: 0.5rem;">AETHERIA</h1>
            <p style="margin-bottom: 2rem; opacity: 0.8;">The Shard Bound</p>
            <button onclick="game.startNewGame()">New Binding</button>
            <button onclick="game.loadGame()">Continue</button>
            <button onclick="game.toggleMute()" id="mute-btn">Audio: ON</button>
        </div>
    </div>

    <div id="screen-pause" class="overlay hidden">
        <div class="panel">
            <h2>Pause</h2>
            <button onclick="game.showMenu('team')">My Team</button>
            <button onclick="game.showMenu('bag')">Inventory</button>
            <button onclick="game.showMenu('lexicon')">Lexicon</button>
            <button onclick="game.resume()">Resume</button>
        </div>
    </div>

    <div id="screen-menu" class="overlay hidden">
        <div class="panel" id="menu-content" style="max-height: 80vh; overflow-y: auto; width: 600px;">
            <!-- Dynamic Content -->
        </div>
        <button onclick="game.resume()">Back</button>
    </div>

    <div id="screen-capture" class="overlay hidden">
        <div class="panel">
            <h2 id="capture-title">Binding Sequence</h2>
            <p>Match the pulse to capture the Shard!</p>
            <div id="capture-ring" style="width: 100px; height: 100px; border: 5px solid var(--accent); border-radius: 50%; margin: 20px auto; position: relative;">
                <div id="capture-needle" style="position: absolute; top: 0; left: 50%; width: 2px; height: 50px; background: white; transform-origin: bottom; transform: rotate(0deg);"></div>
            </div>
            <button id="capture-btn">BIND</button>
        </div>
    </div>
</div>

<script>
/**
 * AETHERIA: THE SHARD BOUND
 * A fully autonomous creature collection RPG.
 */

// --- CORE CONSTANTS & SETTINGS ---
const CONFIG = {
    TILE_SIZE: 48,
    MAP_SIZE: 40, // 40x40 per zone
    FPS: 60,
    SAVE_KEY: 'aetheria_save_v1',
    TYPES: {
        LUMEN: { name: 'Lumen', color: '#ffffaa', beats: 'Umbra', resists: 'Umbra' },
        UMBRA: { name: 'Umbra', color: '#7a52a5', beats: 'Lumen', resists: 'Lumen' },
        TERRA: { name: 'Terra', color: '#aa8844', beats: 'Lumen', resists: 'Umbra' },
        AETHER: { name: 'Aether', color: '#44aaff', beats: 'Terra', resists: 'Lumen' },
        PYRE: { name: 'Pyre', color: '#ff4444', beats: 'Aether', resists: 'Terra' },
        VOID: { name: 'Void', color: '#222222', beats: 'all', resists: 'all' }, // "F" Logic
        PRISM: { name: 'Prism', color: '#ffffff', beats: 'Void', resists: 'all' } // "G" Logic
    }
};

const TYPE_RELATIONS = {
    'Lumen': { 'Umbra': 1.5, 'Terra': 0.5 },
    'Umbra': { 'Lumen': 1.5, 'Terra': 0.5 },
    'Terra': { 'Lumen': 1.5, 'Aether': 0.5 },
    'Aether': { 'Terra': 1.5, 'Pyre': 0.5 },
    'Pyre': { 'Aether': 1.5, 'Umbra': 0.5 },
    'Void': { 'Lumen': 1.2, 'Umbra': 1.2, 'Terra': 1.2, 'Aether': 1.2, 'Pyre': 1.2, 'Prism': 0.5 },
    'Prism': { 'Void': 2.0, 'Lumen': 1.0, 'Umbra': 1.0, 'Terra': 1.0, 'Aether': 1.0, 'Pyre': 1.0 }
};

// --- DATA DEFINITIONS ---

const ABILITIES = {
    "Glimmer": { power: 40, acc: 95, type: 'Lumen', cost: 5, effect: 'none', desc: 'A soft flash of light.' },
    "Soot-Slam": { power: 55, acc: 85, type: 'Terra', cost: 10, effect: 'slow', desc: 'Heavy impact of earth.' },
    "Void-Siphon": { power: 60, acc: 90, type: 'Void', cost: 15, effect: 'drain', desc: 'Steal essence from target.' },
    "Prism-Ray": { power: 75, acc: 80, type: 'Prism', cost: 20, effect: 'crit', desc: 'A beam of refracted light.' },
    "Ember-Singe": { power: 50, acc: 90, type: 'Pyre', cost: 8, effect: 'burn', desc: 'Ignite the surface.' },
    "Static-Pulse": { power: 45, acc: 95, type: 'Aether', cost: 10, effect: 'shock', desc: 'Disrupt neural flow.' },
    "Gloom-Veil": { power: 0, acc: 100, type: 'Umbra', cost: 10, effect: 'barrier', desc: 'Shield with shadows.' },
    "Shatter-Step": { power: 65, acc: 85, type: 'Terra', cost: 15, effect: 'stagger', desc: 'Break the foundation.' },
    "Sky-Lash": { power: 60, acc: 90, type: 'Aether', cost: 12, effect: 'none', desc: 'A whip of lightning.' },
    "Nova-Burst": { power: 110, acc: 70, type: 'Pyre', cost: 30, effect: 'burn', desc: 'Massive explosion.' },
    "Zero-Point": { power: 80, acc: 85, type: 'Void', cost: 20, effect: 'frost', desc: 'Flash freeze space.' },
    "Halo-Beam": { power: 90, acc: 90, type: 'Lumen', cost: 25, effect: 'heal', desc: 'Pure light auras.' },
    "Quake-Core": { power: 100, acc: 75, type: 'Terra', cost: 25, effect: 'stagger', desc: 'Raze the earth.' },
    "Nebula-Sway": { power: 40, acc: 100, type: 'Aether', cost: 5, effect: 'speed', desc: 'Shift perspective.' },
    "Shadow-Stalk": { power: 70, acc: 80, type: 'Umbra', cost: 15, effect: 'crit', desc: 'Attack from blindspot.' },
    "Crown-Flare": { power: 120, acc: 70, type: 'Prism', cost: 30, effect: 'none', desc: 'The apex of radiance.' },
    "Dust-Cloud": { power: 30, acc: 100, type: 'Terra', cost: 5, effect: 'slow', desc: 'Obscure the field.' },
    "Searing-Edge": { power: 65, acc: 90, type: 'Pyre', cost: 12, effect: 'burn', desc: 'A blade of plasma.' },
    "Aether-Bolt": { power: 50, acc: 95, type: 'Aether', cost: 8, effect: 'shock', desc: 'Fast ionic discharge.' },
    "Umbra-Claw": { power: 55, acc: 90, type: 'Umbra', cost: 10, effect: 'none', desc: 'Tearing dark energy.' },
    "Solar-Wind": { power: 45, acc: 100, type: 'Lumen', cost: 10, effect: 'speed', desc: ' Push enemies back.' },
    "Void-Scream": { power: 85, acc: 80, type: 'Void', cost: 18, effect: 'shock', desc: 'Tearing audio rift.' },
    "Crystal-Spike": { power: 70, acc: 85, type: 'Prism', cost: 15, effect: 'none', desc: 'Sharp geometric shards.' },
    "Magma-Vent": { power: 65, acc: 85, type: 'Pyre', cost: 15, effect: 'burn', desc: 'Liquid heat burst.' },
    "Echo-Shock": { power: 50, acc: 95, type: 'Aether', cost: 10, effect: 'none', desc: 'Rhythmic energy pulse.' },
    "Lumen-Swell": { power: 0, acc: 100, type: 'Lumen', cost: 15, effect: 'regen', desc: 'Restore vitality.' },
    "Tectonic-Shift": { power: 90, acc: 80, type: 'Terra', cost: 20, effect: 'stagger', desc: 'Move the ground.' },
    "Night-Terror": { power: 75, acc: 85, type: 'Umbra', cost: 15, effect: 'shock', desc: 'Invoke primal fear.' },
    "Prism-Wall": { power: 0, acc: 100, type: 'Prism', cost: 20, effect: 'barrier', desc: 'Perfect reflection.' },
    "Nova-Swell": { power: 100, acc: 80, type: 'Pyre', cost: 25, effect: 'burn', desc: 'Intense heat wave.' },
    "Aether-Drift": { power: 40, acc: 100, type: 'Aether', cost: 10, effect: 'speed', desc: 'Float weightlessly.' },
    "Void-Crush": { power: 110, acc: 70, type: 'Void', cost: 25, effect: 'none', desc: 'Compress reality.' },
    "Lumina-Strike": { power: 65, acc: 90, type: 'Lumen', cost: 12, effect: 'none', desc: 'Focused light spear.' },
    "Stone-Skin": { power: 0, acc: 100, type: 'Terra', cost: 15, effect: 'defup', desc: 'Harden exterior.' },
    "Umbra-Siphon": { power: 60, acc: 85, type: 'Umbra', cost: 15, effect: 'drain', desc: 'Leach light.' },
    "Prism-Shatter": { power: 80, acc: 80, type: 'Prism', cost: 20, effect: 'crit', desc: 'Fracture the air.' },
    "Pyro-Clasm": { power: 95, acc: 80, type: 'Pyre', cost: 20, effect: 'burn', desc: 'Fiery devastation.' },
    "ionic-Storm": { power: 70, acc: 90, type: 'Aether', cost: 18, effect: 'shock', desc: 'Chaotic sky-fire.' },
    "Null-Void": { power: 50, acc: 100, type: 'Void', cost: 15, effect: 'slow', desc: 'Silence the area.' },
    "Grand-Prism": { power: 150, acc: 60, type: 'Prism', cost: 40, effect: 'none', desc: 'The ultimate spectrum.' }
};

const CREATURE_DATA = {
    // Starters
    "Lumios": { name: "Lumios", type: "Lumen", hp: 45, atk: 52, def: 40, spd: 60, lore: "A floating orb of serene light.", learns: { 1: "Glimmer", 10: "Solar-Wind", 20: "Lumen-Swell" }, transform: { level: 25, item: "SunShard", to: "Solarix" } },
    "Terrox": { name: "Terrox", type: "Terra", hp: 60, atk: 65, def: 50, spd: 30, lore: "A sturdy golem of etched basalt.", learns: { 1: "Soot-Slam", 10: "Dust-Cloud", 20: "Shatter-Step" }, transform: { level: 25, item: "EarthCore", to: "TerraTitan" } },
    "Aeris": { name: "Aeris", type: "Aether", hp: 40, atk: 50, def: 35, spd: 75, lore: "A wispy creature of static clouds.", learns: { 1: "Static-Pulse", 10: "Aether-Bolt", 20: "Nebula-Sway" }, transform: { level: 25, item: "CloudGem", to: "AetherStorm" } },

    // Wilds
    "Gloomite": { name: "Gloomite", type: "Umbra", hp: 40, atk: 45, def: 40, spd: 50, lore: "Hides in the deep shadows of ruins.", learns: { 1: "Umbra-Claw", 12: "Gloom-Veil" }, transform: { level: 30, item: "DarkEssence", to: "UmbraLord" } },
    "Pyrepup": { name: "Pyrepup", type: "Pyre", hp: 42, atk: 55, def: 38, spd: 55, lore: "Their paws leave singed marks.", learns: { 1: "Ember-Singe", 12: "Searing-Edge" }, transform: { level: 30, item: "FireSoot", to: "PyreDrake" } },
    "Shardling": { name: "Shardling", type: "Prism", hp: 35, atk: 48, def: 42, spd: 45, lore: "Crystalline fragments of a lost world.", learns: { 1: "Crystal-Spike", 15: "Prism-Wall" }, transform: { level: 30, item: "PureCrystal", to: "PrismApex" } },
    "Nilith": { name: "Nilith", type: "Void", hp: 50, atk: 50, def: 50, spd: 40, lore: "A creature from the edges of existence.", learns: { 1: "Void-Siphon", 15: "Null-Void" }, transform: { level: 30, item: "VoidSliver", to: "VoidTerror" } },
    "Floris": { name: "Floris", type: "Terra", hp: 55, atk: 40, def: 60, spd: 35, lore: "Rooted deeply in the Echo Plains.", learns: { 1: "Soot-Slam", 12: "Lumen-Swell" } },
    "Zappo": { name: "Zappo", type: "Aether", hp: 38, atk: 58, def: 30, spd: 70, lore: "Moves like a bolt of lightning.", learns: { 1: "Static-Pulse", 12: "Echo-Shock" } },
    "Mistral": { name: "Mistral", type: "Umbra", hp: 45, atk: 42, def: 45, spd: 60, lore: "An elusive spirit of the dusk.", learns: { 1: "Umbra-Claw", 15: "Night-Terror" } },
    "Blazowl": { name: "Blazowl", type: "Pyre", hp: 48, atk: 62, def: 35, spd: 65, lore: "Wings of living flame.", learns: { 1: "Ember-Singe", 15: "Nova-Swell" } },
    "Gladius": { name: "Gladius", type: "Prism", hp: 52, atk: 55, def: 55, spd: 40, lore: "Armed with organic glass blades.", learns: { 1: "Crystal-Spike", 18: "Prism-Shatter" } },
    "Nullon": { name: "Nullon", type: "Void", hp: 60, atk: 45, def: 60, spd: 35, lore: "Absorbs all surrounding sound.", learns: { 1: "Void-Siphon", 20: "Void-Crush" } },
    "Krakos": { name: "Krakos", type: "Terra", hp: 80, atk: 70, def: 70, spd: 20, lore: "A behemoth of the deep caves.", learns: { 1: "Soot-Slam", 20: "Quake-Core" } },
    "Sirocco": { name: "Sirocco", type: "Pyre", hp: 50, atk: 75, def: 40, spd: 70, lore: "A whirlwind of scorching air.", learns: { 1: "Ember-Singe", 20: "Pyro-Clasm" } },
    "Voltane": { name: "Voltane", type: "Aether", hp: 45, atk: 80, def: 35, spd: 85, lore: "Pure electricity in biological form.", learns: { 1: "Static-Pulse", 20: "ionic-Storm" } },
    "Noxis": { name: "Noxis", type: "Umbra", hp: 55, atk: 70, def: 50, spd: 60, lore: "The embodiment of a starless night.", learns: { 1: "Umbra-Claw", 20: "Shadow-Stalk" } },
    "Lumira": { name: "Lumira", type: "Lumen", hp: 50, atk: 60, def: 45, spd: 65, lore: "Guided by the light of the Zenith.", learns: { 1: "Glimmer", 20: "Halo-Beam" } },
    "Onyxian": { name: "Onyxian", type: "Prism", hp: 65, atk: 65, def: 65, spd: 45, lore: "A fortress of reflective onyx.", learns: { 1: "Crystal-Spike", 20: "Grand-Prism" } },
    "Xylos": { name: "Xylos", type: "Void", hp: 70, atk: 60, def: 70, spd: 30, lore: "Ancient keeper of the Null Rift.", learns: { 1: "Void-Siphon", 20: "Zero-Point" } },
    "Zenith": { name: "Zenith", type: "Prism", hp: 100, atk: 90, def: 90, spd: 80, lore: "The ultimate harmony of all colors.", learns: { 1: "Prism-Ray", 10: "Grand-Prism" } },

    // Transformations
    "Solarix": { name: "Solarix", type: "Lumen", hp: 80, atk: 85, def: 70, spd: 90, lore: "A living star of unmatched brilliance.", learns: { 25: "Halo-Beam", 35: "Crown-Flare" } },
    "TerraTitan": { name: "TerraTitan", type: "Terra", hp: 110, atk: 100, def: 110, spd: 40, lore: "The mountain that walks.", learns: { 25: "Quake-Core", 35: "Shatter-Step" } },
    "AetherStorm": { name: "AetherStorm", type: "Aether", hp: 70, atk: 95, def: 60, spd: 110, lore: "A storm that spans the horizons.", learns: { 25: "ionic-Storm", 35: "Nebula-Sway" } },
    "UmbraLord": { name: "UmbraLord", type: "Umbra", hp: 85, atk: 90, def: 75, spd: 80, lore: "Master of the unseen realms.", learns: { 30: "Shadow-Stalk", 40: "Night-Terror" } },
    "PyreDrake": { name: "PyreDrake", type: "Pyre", hp: 90, atk: 110, def: 70, spd: 85, lore: "Breath of incinerating plasma.", learns: { 30: "Nova-Burst", 40: "Pyro-Clasm" } },
    "PrismApex": { name: "PrismApex", type: "Prism", hp: 80, atk: 95, def: 95, spd: 70, lore: "The peak of crystalline evolution.", learns: { 30: "Grand-Prism", 40: "Prism-Shatter" } },
    "VoidTerror": { name: "VoidTerror", type: "Void", hp: 100, atk: 100, def: 100, spd: 60, lore: "The end of all things.", learns: { 30: "Void-Crush", 40: "Zero-Point" } },
    "LumenQueen": { name: "LumenQueen", type: "Lumen", hp: 85, atk: 80, def: 80, spd: 95, lore: "Sovereign of the white light.", learns: { 30: "Halo-Beam", 40: "Solar-Wind" } },
    "TerraBehemoth": { name: "TerraBehemoth", type: "Terra", hp: 130, atk: 120, def: 130, spd: 20, lore: "The world-breaker.", learns: { 30: "Quake-Core", 40: "Stone-Skin" } },
};

const ZONES = [
    { id: 0, name: "Echo Plains", color: "linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d)", enemyPool: ["Lumios", "Terrox", "Aeris", "Floris", "Zappo"], guardian: "LumenQueen", unlockAt: 0 },
    { id: 1, name: "Shatter Coast", color: "linear-gradient(135deg, #203a43, #2c5364)", enemyPool: ["Shardling", "Gloomite", "Mistral", "Gladius"], guardian: "PrismApex", unlockAt: 1 },
    { id: 2, name: "Pyre Peaks", color: "linear-gradient(135deg, #4b1212, #ff4b2b)", enemyPool: ["Pyrepup", "Blazowl", "Sirocco", "Lumina"], guardian: "PyreDrake", unlockAt: 2 },
    { id: 3, name: "Aether Void", color: "linear-gradient(135deg, #0f0c29, #302b63, #24243e)", enemyPool: ["Nilith", "Nullon", "Xylos", "Voltane"], guardian: "VoidTerror", unlockAt: 3 },
    { id: 4, name: "Obsidian Reach", color: "linear-gradient(135deg, #000000, #434343)", enemyPool: ["Noxis", "Krakos", "Onyxian", "Gloomite"], guardian: "UmbraLord", unlockAt: 4 },
    { id: 5, name: "Zenith Spire", color: "linear-gradient(135deg, #ffffff, #8e9eab)", enemyPool: ["Zenith", "VoidTerror", "PrismApex"], guardian: "Zenith", unlockAt: 5 },
];

const ITEMS = {
    "Binding Orb": { type: "capture", tier: 1, desc: "Basic capture device." },
    "Binding Sphere": { type: "capture", tier: 2, desc: "Enhanced stability." },
    "Binding Core": { type: "capture", tier: 3, desc: "Maximum binding force." },
    "Vital-Dew": { type: "heal", value: 50, desc: "Heals a creature for 50 HP." },
    "Full-Restore": { type: "heal", value: 'full', desc: "Fully restores HP." },
    "SunShard": { type: "catalyst", target: "Lumios", desc: "Crystallized sunlight." },
    "EarthCore": { type: "catalyst", target: "Terrox", desc: "The heart of a mountain." },
    "CloudGem": { type: "catalyst", target: "Aeris", desc: "A condensed storm-cloud." },
    "DarkEssence": { type: "catalyst", target: "Gloomite", desc: "Pure concentrated shadow." },
    "FireSoot": { type: "catalyst", target: "Pyrepup", desc: "Ash from a dying star." },
    "PureCrystal": { type: "catalyst", target: "Shardling", desc: "A flawlessly clear prism." },
    "VoidSliver": { type: "catalyst", target: "Nilith", desc: "A fragment of the void." },
};

// --- GAME ENGINE ---

class Game {
    constructor() {
        this.canvas = document.getElementById('mainCanvas');
        this.ctx = this.canvas.getContext('2d');
        this.muted = false;
        this.state = 'TITLE'; // TITLE, OVERWORLD, BATTLE, MENU, DIALOGUE, CAPTURE
        this.player = {
            x: 5, y: 5,
            zone: 0,
            party: [],
            inventory: { "Binding Orb": 5, "Vital-Dew": 3 },
            unlockedZones: [0],
            anchorsDefeated: [],
            savePoint: { x: 5, y: 5, zone: 0 }
        };
        this.currentBattle = null;
        this.dialogueQueue = [];
        this.dialogueIndex = 0;
        this.particles = [];
        this.input = { w: false, a: false, s: false, d: false };

        this.initCanvas();
        this. setupControls();
        this.loop();
    }

    initCanvas() {
        this.canvas.width = 800;
        this.canvas.height = 600;
    }

    setupControls() {
        window.addEventListener('keydown', e => this.handleKey(e.key, true));
        window.addEventListener('keyup', e => this.handleKey(e.key, false));
        
        // Touch buttons
        const bindBtn = (id, key) => {
            const btn = document.getElementById(id);
            btn.onmousedown = () => this.handleKey(key, true);
            btn.onmouseup = () => this.handleKey(key, false);
            btn.ontouchstart = (e) => { e.preventDefault(); this.handleKey(key, true); };
            btn.ontouchend = (e) => { e.preventDefault(); this.handleKey(key, false); };
        };
        bindBtn('btn-up', 'w'); bindBtn('btn-down', 's');
        bindBtn('btn-left', 'a'); bindBtn('btn-right', 'd');

        document.getElementById('dialogue-box').onclick = () => this.nextDialogue();
        document.getElementById('capture-btn').onclick = () => this.attemptCapture();
    }

    handleKey(key, isDown) {
        const k = key.toLowerCase();
        if (k === 'w' || k === 'arrowup') this.input.w = isDown;
        if (k === 'a' || k === 'arrowleft') this.input.a = isDown;
        if (k === 's' || k === 'arrowdown') this.input.s = isDown;
        if (k === 'd' || k === 'arrowright') this.input.d = isDown;
        if (isDown && k === 'escape') this.togglePause();
    }

    startNewGame() {
        this.state = 'DIALOGUE';
        document.getElementById('screen-title').classList.add('hidden');
        this.dialogueQueue = [
            "Welcome, Seeker, to the world of Aetheria...",
            "The Shards of the old world have manifested as creatures of elemental energy.",
            "You are a Binder, one who can unite these fragments.",
            "Choose your first companion to begin your journey."
        ];
        this.dialogueIndex = 0;
        this.showDialogue();
        
        // After intro, trigger starter selection
        setTimeout(() => {
            if (this.dialogueIndex >= this.dialogueQueue.length) {
                this.showStarterSelection();
            }
        }, 100);
    }

    showStarterSelection() {
        this.state = 'MENU';
        const content = document.getElementById('menu-content');
        content.innerHTML = `<h2>Choose Your Starter</h2><div style="display:flex; gap:20px; justify-content:center;">`;
        const starters = ["Lumios", "Terrox", "Aeris"];
        starters.forEach(s => {
            const data = CREATURE_DATA[s];
            content.innerHTML += `
                <div class="panel" style="width:180px; cursor:pointer; background: rgba(255,255,255,0.05);" onclick="game.pickStarter('${s}')">
                    <div style="font-weight:bold; color:var(--accent)">${data.name}</div>
                    <div style="font-size:0.8rem; margin:10px 0;">${data.type}</div>
                    <div style="font-size:0.7rem; opacity:0.7;">${data.lore}</div>
                </div>
            `;
        });
        content.innerHTML += `</div>`;
        document.getElementById('screen-menu').classList.remove('hidden');
    }

    pickStarter(name) {
        const creature = this.createCreature(name, 5);
        this.player.party.push(creature);
        document.getElementById('screen-menu').classList.add('hidden');
        this.state = 'OVERWORLD';
        this.dialogueQueue = ["You have bound " + name + "! Now, explore the Echo Plains. Use WASD to move."];
        this.dialogueIndex = 0;
        this.showDialogue();
    }

    createCreature(species, level) {
        const data = CREATURE_DATA[species];
        const c = {
            species,
            level,
            hp: data.hp + (level * 2),
            maxHp: data.hp + (level * 2),
            atk: data.atk + (level * 1.5),
            def: data.def + (level * 1.2),
            spd: data.spd + (level * 1.1),
            type: data.type,
            exp: 0,
            nextLevel: 100,
            moves: [],
            status: null
        };
        // Initial moves
        Object.keys(data.learns).forEach(lvl => {
            if (level >= parseInt(lvl)) c.moves.push(data.learns[lvl]);
        });
        return c;
    }

    showDialogue() {
        const box = document.getElementById('dialogue-box');
        const text = document.getElementById('dialogue-text');
        box.style.display = 'block';
        text.innerText = this.dialogueQueue[this.dialogueIndex];
    }

    nextDialogue() {
        this.dialogueIndex++;
        if (this.dialogueIndex < this.dialogueQueue.length) {
            this.showDialogue();
        } else {
            document.getElementById('dialogue-box').style.display = 'none';
            if (this.state === 'DIALOGUE') this.state = 'OVERWORLD';
        }
    }

    togglePause() {
        if (this.state === 'BATTLE') return;
        if (this.state === 'OVERWORLD') {
            this.state = 'PAUSE';
            document.getElementById('screen-pause').classList.remove('hidden');
        } else if (this.state === 'PAUSE') {
            this.resume();
        }
    }

    resume() {
        document.getElementById('screen-pause').classList.add('hidden');
        document.getElementById('screen-menu').classList.add('hidden');
        this.state = 'OVERWORLD';
    }

    showMenu(type) {
        this.state = 'MENU';
        document.getElementById('screen-pause').classList.add('hidden');
        document.getElementById('screen-menu').classList.remove('hidden');
        const content = document.getElementById('menu-content');
        
        if (type === 'team') {
            content.innerHTML = `<h2>Your Bound Shards</h2>`;
            this.player.party.forEach((c, i) => {
                content.innerHTML += `
                    <div class="panel" style="margin:10px 0; text-align:left; display:flex; justify-content:space-between; align-items:center;">
                        <div>
                            <strong>${c.species}</strong> (Lv.${c.level}) - <span style="color:${CONFIG.TYPES[c.type].color}">${c.type}</span><br>
                            HP: ${c.hp}/${c.maxHp} | ATK: ${Math.floor(c.atk)} | DEF: ${Math.floor(c.def)} | SPD: ${Math.floor(c.spd)}
                        </div>
                        <div>
                            ${c.moves.map(m => `<div style="font-size:0.7rem;">${m}</div>`).join('')}
                        </div>
                    </div>
                `;
            });
        } else if (type === 'bag') {
            content.innerHTML = `<h2>Inventory</h2>`;
            for (let item in this.player.inventory) {
                const qty = this.player.inventory[item];
                if (qty > 0) {
                    content.innerHTML += `<div class="panel" style="margin:10px 0; display:flex; justify-content:space-between;">
                        <span>${item} x${qty}</span>
                        <button onclick="game.useItem('${item}')">Use</button>
                    </div>`;
                }
            }
        } else if (type === 'lexicon') {
            content.innerHTML = `<h2>Aetherian Lexicon</h2>`;
            Object.keys(CREATURE_DATA).forEach(k => {
                const d = CREATURE_DATA[k];
                content.innerHTML += `<div style="margin:5px 0; font-size:0.8rem;"><strong>${d.name}</strong> [${d.type}]: ${d.lore}</div>`;
            });
        }
    }

    useItem(itemName) {
        const item = ITEMS[itemName];
        if (!item) return;
        if (item.type === 'heal') {
            if (this.player.party.length === 0) return;
            const target = this.player.party[0];
            if (item.value === 'full') target.hp = target.maxHp;
            else target.hp = Math.min(target.maxHp, target.hp + item.value);
            this.player.inventory[itemName]--;
            this.showMenu('bag');
        } else if (item.type === 'catalyst') {
            // Transformation logic: Find creature of that base species
            const index = this.player.party.findIndex(c => c.species === item.target);
            if (index !== -1) {
                const c = this.player.party[index];
                const data = CREATURE_DATA[c.species];
                if (c.level >= data.transform.level) {
                    const nextSpecies = data.transform.to;
                    const nextData = CREATURE_DATA[nextSpecies];
                    c.species = nextSpecies;
                    c.type = nextData.type;
                    c.atk += 20; c.def += 20; c.hp += 40; c.maxHp += 40;
                    c.moves.push(...Object.keys(nextData.learns).filter(l => c.level >= parseInt(l)).map(l => nextData.learns[l]));
                    this.player.inventory[itemName]--;
                    alert(`${c.species} has evolved!`);
                } else {
                    alert(`${c.species} is not yet ready to transform.`);
                }
            } else {
                alert("You have no creature that can use this catalyst.");
            }
            this.showMenu('bag');
        }
    }

    // --- OVERWORLD LOGIC ---

    updateOverworld() {
        let moved = false;
        if (this.input.w) { this.player.y -= 0.1; moved = true; }
        if (this.input.s) { this.player.y += 0.1; moved = true; }
        if (this.input.a) { this.player.x -= 0.1; moved = true; }
        if (this.input.d) { this.player.x += 0.1; moved = true; }

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

        if (moved) {
            // Encounter check
            if (Math.random() < 0.005) {
                this.startBattle();
            }
        }
    }

    drawOverworld() {
        const zone = ZONES[this.player.zone];
        const grad = this.ctx.createLinearGradient(0,0, this.canvas.width, this.canvas.height);
        grad.addColorStop(0, '#1a1a2e');
        grad.addColorStop(1, '#16213e');
        this.ctx.fillStyle = grad;
        this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);

        // Draw grid/terrain
        this.ctx.strokeStyle = 'rgba(255,255,255,0.05)';
        this.ctx.lineWidth = 1;
        for (let i = 0; i <= CONFIG.MAP_SIZE; i++) {
            this.ctx.beginPath();
            this.ctx.moveTo(i * (this.canvas.width / CONFIG.MAP_SIZE), 0);
            this.ctx.lineTo(i * (this.canvas.width / CONFIG.MAP_SIZE), this.canvas.height);
            this.ctx.stroke();
            this.ctx.beginPath();
            this.ctx.moveTo(0, i * (this.canvas.height / CONFIG.MAP_SIZE));
            this.ctx.lineTo(this.canvas.width, i * (this.canvas.height / CONFIG.MAP_SIZE));
            this.ctx.stroke();
        }

        // Player
        this.ctx.fillStyle = varColor('--accent');
        this.ctx.beginPath();
        this.ctx.arc(this.player.x * (this.canvas.width / CONFIG.MAP_SIZE), this.player.y * (this.canvas.height / CONFIG.MAP_SIZE), 8, 0, Math.PI*2);
        this.ctx.fill();
        this.ctx.shadowBlur = 15;
        this.ctx.shadowColor = varColor('--accent');
        this.ctx.stroke();
        this.ctx.shadowBlur = 0;

        // HUD update
        document.getElementById('hud-zone').innerText = `Zone: ${zone.name}`;
        document.getElementById('hud-party').innerText = `Creatures: ${this.player.party.length}/6`;
    }

    // --- BATTLE SYSTEM ---

    startBattle() {
        this.state = 'BATTLE';
        const zone = ZONES[this.player.zone];
        const enemySpecies = zone.enemyPool[Math.floor(Math.random() * zone.enemyPool.length)];
        const level = 5 + (this.player.zone * 5) + Math.floor(Math.random() * 3);
        const enemy = this.createCreature(enemySpecies, level);

        this.currentBattle = {
            player: this.player.party[0], 
            enemy: enemy,
            turn: 'player',
            turnQueue: [],
            log: "A wild " + enemySpecies + " appeared!"
        };

        document.getElementById('battle-ui').style.display = 'grid';
        this.updateBattleUI();
    }

    updateBattleUI() {
        const b = this.currentBattle;
        const stats = document.getElementById('battle-stats');
        stats.innerHTML = `
            <div style="margin-bottom:20px;">
                <strong>${b.enemy.species}</strong> (Lv.${b.enemy.level})<br>
                <div class="stat-bar-container"><div class="stat-bar-fill hp-fill" style="width:${(b.enemy.hp/b.enemy.maxHp)*100}%"></div></div>
            </div>
            <div>
                <strong>${b.player.species}</strong> (Lv.${b.player.level})<br>
                <div class="stat-bar-container"><div class="stat-bar-fill hp-fill" style="width:${(b.player.hp/b.player.maxHp)*100}%"></div></div>
                <div style="font-size:0.7rem;">HP: ${Math.floor(b.player.hp)} / ${Math.floor(b.player.maxHp)}</div>
            </div>
        `;

        const actions = document.getElementById('battle-actions');
        actions.innerHTML = '';
        if (b.turn === 'player') {
            b.player.moves.forEach(m => {
                const btn = document.createElement('button');
                btn.innerText = m;
                btn.onclick = () => this.executeMove(m);
                actions.appendChild(btn);
            });
            const captureBtn = document.createElement('button');
            captureBtn.innerText = "Bind Shard";
            captureBtn.onclick = () => this.initCaptureSequence();
            actions.appendChild(captureBtn);
        } else {
            actions.innerHTML = `<div style="grid-column: span 2; text-align:center; font-style:italic; padding:20px;">Enemy is calculating...</div>`;
        }
    }

    executeMove(moveName) {
        const move = ABILITIES[moveName];
        const b = this.currentBattle;
        
        const dmg = this.calculateDamage(b.player, b.enemy, move);
        b.enemy.hp -= dmg;
        
        this.logBattle(`Your ${b.player.species} used ${moveName} for ${Math.floor(dmg)} damage!`);
        
        if (b.enemy.hp <= 0) {
            this.winBattle();
        } else {
            b.turn = 'enemy';
            this.updateBattleUI();
            setTimeout(() => this.enemyTurn(), 1000);
        }
    }

    enemyTurn() {
        const b = this.currentBattle;
        const moveName = b.enemy.moves[Math.floor(Math.random() * b.enemy.moves.length)];
        const move = ABILITIES[moveName];
        
        const dmg = this.calculateDamage(b.enemy, b.player, move);
        b.player.hp -= dmg;
        
        this.logBattle(`${b.enemy.species} used ${moveName} for ${Math.floor(dmg)} damage!`);

        if (b.player.hp <= 0) {
            alert("Your creature fainted! Returning to last shrine...");
            this.player.x = this.player.savePoint.x;
            this.player.y = this.player.savePoint.y;
            this.player.party.forEach(c => c.hp = c.maxHp);
            this.endBattle();
        } else {
            b.turn = 'player';
            this.updateBattleUI();
        }
    }

    calculateDamage(attacker, defender, move) {
        const mult = (TYPE_RELATIONS[attacker.type] && TYPE_RELATIONS[attacker.type][defender.type]) || 1.0;
        const stab = (move.type === attacker.type) ? 1.25 : 1.0;
        const baseDmg = (0.4 * attacker.level * attacker.atk / defender.def * mult * stab);
        return Math.floor(baseDmg + Math.random() * 5);
    }

    logBattle(msg) {
        console.log(msg);
        // In a full version, we'd have a log scroll
    }

    winBattle() {
        const b = this.currentBattle;
        const expGain = 50 + (b.enemy.level * 10);
        b.player.exp += expGain;
        if (b.player.exp >= b.player.nextLevel) {
            b.player.level++;
            b.player.exp -= b.player.nextLevel;
            b.player.maxHp += 5; b.player.hp = b.player.maxHp;
            b.player.atk += 2; b.player.def += 2; b.player.spd += 2;
            alert(`${b.player.species} leveled up to ${b.player.level}!`);
        }
        alert(`Victory! Gained ${expGain} EXP.`);
        this.endBattle();
    }

    endBattle() {
        this.state = 'OVERWORLD';
        document.getElementById('battle-ui').style.display = 'none';
        this.currentBattle = null;
    }

    initCaptureSequence() {
        this.state = 'CAPTURE';
        document.getElementById('screen-capture').classList.remove('hidden');
        this.captureAngle = 0;
        this.captureDir = 1;
        this.captureInterval = setInterval(() => {
            this.captureAngle += 4 * this.captureDir;
            if (this.captureAngle > 360 || this.captureAngle < 0) this.captureDir *= -1;
            document.getElementById('capture-needle').style.transform = `rotate(${this.captureAngle}deg)`;
        }, 16);
    }

    attemptCapture() {
        const b = this.currentBattle;
        clearInterval(this.captureInterval);
        
        // Simple success check: if angle is between 340 and 20 (top)
        const normAngle = this.captureAngle % 360;
        const success = (normAngle > 340 || normAngle < 20) || (Math.random() < (1 - b.enemy.hp/b.enemy.maxHp));
        
        if (success && this.player.inventory["Binding Orb"] > 0) {
            this.player.inventory["Binding Orb"]--;
            this.player.party.push({...b.enemy});
            alert(`Successfully bound ${b.enemy.species}!`);
        } else {
            alert("The binding failed...");
        }

        document.getElementById('screen-capture').classList.add('hidden');
        this.state = 'BATTLE';
        this.updateBattleUI();
    }

    // --- MAIN LOOP ---

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

    update() {
        if (this.state === 'OVERWORLD') {
            this.updateOverworld();
        }
    }

    draw() {
        if (this.state === 'OVERWORLD' || this.state === 'DIALOGUE') {
            this.drawOverworld();
        } else if (this.state === 'BATTLE') {
            const b = this.currentBattle;
            const ctx = this.ctx;
            ctx.fillStyle = '#050510';
            ctx.fillRect(0,0, this.canvas.width, this.canvas.height);
            
            // Enemy
            ctx.fillStyle = CONFIG.TYPES[b.enemy.type].color;
            ctx.beginPath();
            ctx.arc(600, 200, 40, 0, Math.PI*2);
            ctx.fill();
            ctx.fillStyle = 'white';
            ctx.fillText(b.enemy.species, 570, 150);

            // Player
            ctx.fillStyle = CONFIG.TYPES[b.player.type].color;
            ctx.beginPath();
            ctx.arc(200, 400, 50, 0, Math.PI*2);
            ctx.fill();
            ctx.fillStyle = 'white';
            ctx.fillText(b.player.species, 170, 340);
        } else if (this.state === 'MENU' || this.state === 'PAUSE') {
            this.ctx.fillStyle = 'black';
            this.ctx.fillRect(0,0, this.canvas.width, this.canvas.height);
        }
    }

    toggleMute() {
        this.muted = !this.muted;
        document.getElementById('mute-btn').innerText = `Audio: ${this.muted ? 'OFF' : 'ON'}`;
    }

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

    saveGame() {
        localStorage.setItem(CONFIG.SAVE_KEY, JSON.stringify(this.player));
    }
}

function varColor(name) {
    return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
}

const game = new Game();

</script>
</body>
</html>
<!-- agent-meta {"model":"gemma-4-31b","provider":"cerebras","persona":"middle","sessionId":"8c2cb690-c0fe-4123-b698-e216eddd2275","tokensIn":18544,"tokensOut":14733,"tokensTotal":33277,"turns":2,"toolCalls":1,"failedToolCalls":0,"timestamp":"2026-07-14T16:16:08.082Z"} -->