# Aether Chronicles — Design Document ## 1. Architecture ``` ┌─────────────────────────────────────────────────┐ │ Browser (JS) │ │ ┌─────────────┐ ┌──────────┐ ┌─────────────┐ │ │ │ Renderer │ │ Input │ │ UI Manager │ │ │ │ (Canvas) │ │ Handler │ │ (DOM) │ │ │ └──────┬──────┘ └────┬─────┘ └──────┬──────┘ │ │ └───────────────┴───────────────┘ │ │ │ │ │ Game Client (JS) │ └────────────────────────┬─────────────────────────┘ │ REST + WebSocket ┌────────────────────────┴─────────────────────────┐ │ Python Backend (FastAPI) │ │ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │ │ │ Game │ │ LLM │ │ World State │ │ │ │ Engine │ │ Bridge │ │ (SQLite) │ │ │ └────┬─────┘ └────┬─────┘ └───────┬───────┘ │ │ │ │ │ │ │ └─────────────┴─────────────────┘ │ │ │ │ │ ┌──────┴──────┐ │ │ │ Ollama │ │ │ │ (gemma4) │ │ │ └─────────────┘ │ └──────────────────────────────────────────────────┘ ``` ## 2. Game State (SQLite Schema) ```sql -- Player CREATE TABLE player ( id INTEGER PRIMARY KEY, name TEXT, class TEXT DEFAULT 'wanderer', level INTEGER DEFAULT 1, exp INTEGER DEFAULT 0, hp INTEGER DEFAULT 100, max_hp INTEGER DEFAULT 100, sp INTEGER DEFAULT 50, max_sp INTEGER DEFAULT 50, str INTEGER DEFAULT 10, agi INTEGER DEFAULT 10, int INTEGER DEFAULT 10, vit INTEGER DEFAULT 10, dex INTEGER DEFAULT 10, luk INTEGER DEFAULT 5, x REAL DEFAULT 400, y REAL DEFAULT 300, map_id TEXT DEFAULT 'eichenhafen', gold INTEGER DEFAULT 100 ); -- Inventory CREATE TABLE inventory ( id INTEGER PRIMARY KEY, player_id INTEGER, item_id TEXT, quantity INTEGER DEFAULT 1, equipped INTEGER DEFAULT 0 ); -- World Events (LLM-generated) CREATE TABLE world_events ( id INTEGER PRIMARY KEY, map_id TEXT, event_type TEXT, description TEXT, data_json TEXT, active INTEGER DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- NPC Dialogues (LLM-generated, cached) CREATE TABLE npc_dialogues ( id INTEGER PRIMARY KEY, npc_id TEXT, mood TEXT, dialogue TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Quests CREATE TABLE quests ( id INTEGER PRIMARY KEY, quest_type TEXT, name TEXT, description TEXT, npc_id TEXT, map_id TEXT, min_level INTEGER, reward_gold INTEGER, reward_exp INTEGER, status TEXT DEFAULT 'available' ); ``` ## 3. LLM Integration ### Prompt Templates ```python # Event Generation EVENT_PROMPT = """You are the Dungeon Master for Aether Chronicles. Current map: {map_name} Current time: {time_of_day} Player level: {player_level} Recent events: {recent_events} Generate ONE optional event for this map. Rules: - Must be optional (player can ignore it) - Must not block any paths - Must not move any NPCs - Must not be required for progression - Keep it short (2-3 sentences) Respond in JSON: { "type": "weather|encounter|discovery|npc_mood", "description": "...", "effect": "buff|debuff|spawn|dialogue", "data": { ... } } """ # NPC Dialogue DIALOGUE_PROMPT = """You are {npc_name}, a {npc_role} in {city_name}. Your personality: {personality} Current mood: {mood} The player ({player_class}, level {player_level}) approaches you. Say something in character (2-3 sentences). Be brief. """ ``` ### Validation Rules ```python def validate_event(event: dict, map_id: str) -> bool: # Never block paths if event.get("effect") == "block_path": return False # Never move NPCs if event.get("effect") == "move_npc": return False # Never required for main quest if event.get("required") == True: return False # Must be optional if event.get("optional") == False: return False return True ``` ## 4. Map System ### Fixed Maps ``` eichenhafen — Starting city (harbor) eichenhafen_field — Field outside starting city (main road) sonnenfeld — Central trade city sonnenfeld_field — Field outside trade city nebelgipfel — Mountain fortress city nebelgipfel_path — Mountain path (dangerous) ``` ### Dynamic Maps (LLM-generated layouts) ``` side_dungeon_1 — Generated dungeon layout side_dungeon_2 — Generated dungeon layout cave_random — Generated cave layout ``` ## 5. Combat Formulas ```python # Physical damage damage = (atk * (1 + str/100)) - (target_def * 0.5) damage = max(1, damage) # minimum 1 damage # Magic damage magic_damage = (matk * (1 + int/100)) * element_multiplier # Hit rate hit_rate = min(95, 80 + (dex - target_agi) * 2) # Critical rate crit_rate = min(50, 5 + luk * 2) # EXP needed for next level exp_needed = int(100 * (level ** 1.5)) ``` ## 6. Milestone Details ### M1: Project Setup + Tilemap (1-2 hours) - HTML5 Canvas setup - Isometric tilemap renderer - Tile loading from JSON - Camera with mouse pan/zoom - Basic tileset (grass, water, path, building) ### M2: Click-to-Move (1-2 hours) - A* pathfinding implementation - Click destination → character walks path - Collision detection (walls, water) - Smooth movement animation ### M3: Player Stats + UI (1-2 hours) - HP/SP bars (DOM overlay) - Skill bar (1-0 keys) - Character info panel - EXP bar ### M4: Combat (2-3 hours) - Click enemy → auto-attack - Damage numbers floating - Death animation - EXP gain on kill - Aggro range for monsters ### M5: Monster AI (2-3 hours) - Spawn system - Patrol behavior - Aggro + chase - Respawn timer - Drop table ### M6: City + NPCs (3-4 hours) - Eichenhafen map layout - NPC sprites + interaction - Shop interface - Storage interface - Class master NPC ### M7: LLM Integration (3-4 hours) - Ollama API bridge - Event generation (periodic) - NPC dialogue generation - Event validation - Caching to reduce LLM calls ### M8: Quest System (2-3 hours) - Fixed main quests - LLM side quests (validated) - Quest log UI - Turn-in mechanics ### M9: Inventory + Equipment (2-3 hours) - Item system - Equipment slots - Stats from equipment - Drop/pickup ### M10: Class System (3-4 hours) - Class change at level 10 - Skill trees - Skill effects in combat - 2nd class at level 40