# Mana Loop - Project Architecture Guide This document provides a comprehensive overview of the project architecture for AI agents working on this codebase. --- ## 🔑 Git Credentials (SAVE THESE) **Repository:** `git@gitea.tailf367e3.ts.net:Anexim/Mana-Loop.git` **HTTPS URL with credentials:** ``` https://zhipu:5LlnutmdsC2WirDwWgnZuRH7@gitea.tailf367e3.ts.net/Anexim/Mana-Loop.git ``` **Credentials:** - **User:** zhipu - **Email:** zhipu@local.local - **Password:** 5LlnutmdsC2WirDwWgnZuRH7 **To configure git:** ```bash git config --global user.name "zhipu" git config --global user.email "zhipu@local.local" ``` --- ## ⚠️ MANDATORY GIT WORKFLOW - MUST BE FOLLOWED **Before starting ANY work, you MUST:** 1. **Pull the latest changes:** ```bash cd /home/z/my-project && git pull origin master ``` 2. **Do your task** - Make all necessary code changes 3. **Before finishing, commit and push:** ```bash cd /home/z/my-project git add -A git commit -m "descriptive message about changes" git push origin master ``` **This workflow is ENFORCED and NON-NEGOTIABLE.** Every agent session must: - Start with `git pull` - End with `git add`, `git commit`, `git push` **Git Remote:** `git@gitea.tailf367e3.ts.net:Anexim/Mana-Loop.git` --- ## Project Overview **Mana Loop** is an incremental/idle game built with: - **Framework**: Next.js 16 with App Router - **Language**: TypeScript 5 - **Styling**: Tailwind CSS 4 with shadcn/ui components - **State Management**: Zustand with persist middleware - **Database**: Prisma ORM with SQLite (for persistence features) ## Core Game Loop 1. **Mana Gathering**: Click or auto-generate mana over time 2. **Studying**: Spend mana to learn skills and spells 3. **Combat**: Climb the Spire, defeat guardians, sign pacts 4. **Crafting**: Enchant equipment with spell effects 5. **Prestige**: Reset progress for permanent bonuses (Insight) ## Directory Structure ``` src/ ├── app/ │ ├── page.tsx # Main game UI (~548 lines, reduced via component extraction) │ ├── layout.tsx # Root layout with providers │ └── api/ # API routes (minimal use) ├── components/ │ ├── ui/ # shadcn/ui components (auto-generated) │ └── game/ │ ├── index.ts # Barrel exports │ ├── ActionButtons.tsx # Current action display with progress indicator │ ├── CalendarDisplay.tsx # Day calendar with incursion indicators │ ├── CraftingProgress.tsx # Design/preparation/application progress bars │ ├── StudyProgress.tsx # Current study progress with cancel button │ ├── ManaDisplay.tsx # Mana/gathering section with progress bar │ ├── TimeDisplay.tsx # Day/hour display with pause toggle │ └── tabs/ # Tab-specific components (Task 2: all tabs refactored) │ ├── index.ts # Tab component exports │ ├── CraftingTab.tsx # Enchantment crafting UI (~164 lines) │ ├── LabTab.tsx # Skill upgrade and lab features │ ├── SpellsTab.tsx # Spell management and equipment spells │ ├── SpireTab.tsx # Combat with Spire Mode (~354 lines, Task 2 overhaul) │ ├── StatsTab.tsx # Player statistics (~251 lines, Task 2: elements locked) │ ├── SkillsTab.tsx # Skill tree display (~371 lines, Task 2: Ascension deleted) │ ├── EquipmentTab.tsx # Gear management (~435 lines) │ ├── DebugTab.tsx # Debug tools (~34 lines, Task 2: added Pact buttons) │ └── LootTab.tsx # Loot display (~48 lines, Task 2: Transference removed) └── lib/ ├── game/ │ ├── store.ts # Zustand store (~2812 lines, main state + tick logic) │ ├── crafting-slice.ts # Equipment/enchantment logic (~1100 lines, from store.ts) │ ├── computed-stats.ts # Computed stats functions (~12 lines, simplified) │ ├── navigation-slice.ts # Floor navigation actions (~75 lines) │ ├── study-slice.ts # Study system actions (~210 lines) │ ├── familiar-slice.ts # Familiar system actions │ ├── effects.ts # Unified effect computation │ ├── upgrade-effects.ts # Skill upgrade effect definitions │ ├── constants.ts # Game definitions (spells, skills, etc.) │ ├── skill-evolution.ts # Skill tier progression paths (~3400 lines) │ ├── types.ts # TypeScript interfaces │ ├── formatting.ts # Display formatters │ ├── utils.ts # Utility functions │ └── data/ │ ├── equipment.ts # Equipment type definitions │ └── enchantment-effects.ts # Enchantment effect catalog └── utils.ts # General utilities (cn function) ``` *Note: A complete, up-to-date project tree is automatically generated on each commit and saved to `docs/project-structure.txt`. This file is generated by the pre-commit hook using `.husky/scripts/generate-project-tree.js` and respects `.gitignore` rules.* ## Key Systems ### 0. Task 2 Completion Summary **Task 2 has been completed successfully (12/12 tasks done)!** Key changes made in Task 2: - **ActionButtons Rework**: Removed manual selection, auto-transition to Meditate after actions - **SpireTab Overhaul**: Added "Climb the Spire" button, implemented Spire Mode with exit condition - **Equipment System**: Added support for 2-Handed Weapons, Staves now block offhand slot - **Research Locking**: Prevent switching topics while study in progress - **DebugTab Update**: Added Invoker Debugging Buttons for Pacts - **Combat UI Fix**: Fixed Casting Bar progress animation - **Crafting Limits**: Disabled Prepare for non-enchanted items, limited Design to owned gear types - **System Integrity**: Fixed Show Component Names debug option for all components - **StatsTab**: Locked Fire/Water/Air/Earth at start, only Transference unlocked - **LootTab**: Removed Transference from essence list (not lootable) - **Ascension Skills**: Deleted all Ascension skills - **Mana Well Fix**: Fixed Deep Basin upgrade multiplier values **Context File Approach for Sub-Agents:** During Task 2, context files were created in `docs/` to guide sub-agents: - `update_agents_context.md` - Context for updating AGENTS.md - `update_game_briefing_context.md` - Context for updating GAME_BRIEFING.md - `update_skills_context.md` - Context for updating skills.md This approach proved effective for delegating documentation updates to sub-agents. ### 1. State Management (`store.ts`) The game uses a Zustand store organized with **slice pattern** for better maintainability: #### Store Slices - **Main Store** (`store.ts`): Core state, tick logic, and main actions (~2812 lines) - **Navigation Slice** (`navigation-slice.ts`): Floor navigation (setClimbDirection, changeFloor) (~75 lines) - **Study Slice** (`study-slice.ts`): Study system (startStudyingSkill, startStudyingSpell, cancelStudy) (~210 lines) - **Crafting Slice** (`crafting-slice.ts`): Equipment/enchantment (createEquipmentInstance, startDesigningEnchantment) (~1100 lines) - **Familiar Slice** (`familiar-slice.ts`): Familiar system (addFamiliar, removeFamiliar) - **NOTE: File does not currently exist** #### Computed Stats (`computed-stats.ts`) Extracted utility functions for stat calculations: - `computeMaxMana()`, `computeRegen()`, `computeEffectiveRegen()` - `calcDamage()`, `calcInsight()`, `getElementalBonus()` - `getFloorMaxHP()`, `getFloorElement()`, `getMeditationBonus()` - `canAffordSpellCost()`, `deductSpellCost()` ```typescript interface GameState { // Time day: number; hour: number; paused: boolean; // Mana rawMana: number; elements: Record; // Combat currentFloor: number; floorHP: number; activeSpell: string; castProgress: number; // Progression skills: Record; spells: Record; skillUpgrades: Record; skillTiers: Record; // Equipment equipmentInstances: Record; equippedInstances: Record; enchantmentDesigns: EnchantmentDesign[]; // Prestige insight: number; prestigeUpgrades: Record; signedPacts: number[]; } ``` ### 2. Effect System (`effects.ts`) **CRITICAL**: All stat modifications flow through the unified effect system. ```typescript // Effects come from two sources: // 1. Skill Upgrades (milestone bonuses) // 2. Equipment Enchantments (crafted bonuses) getUnifiedEffects(state) => UnifiedEffects { maxManaBonus, maxManaMultiplier, regenBonus, regenMultiplier, clickManaBonus, clickManaMultiplier, baseDamageBonus, baseDamageMultiplier, attackSpeedMultiplier, critChanceBonus, critDamageMultiplier, studySpeedMultiplier, specials: Set, // Special effect IDs } ``` **When adding new stats**: 1. Add to `ComputedEffects` interface in `upgrade-effects.ts` 2. Add mapping in `computeEquipmentEffects()` in `effects.ts` 3. Apply in the relevant game logic (tick, damage calc, etc.) ### 3. Combat System Combat uses a **cast speed** system: - Each spell has `castSpeed` (casts per hour) - Cast progress accumulates: `progress += castSpeed * attackSpeedMultiplier * HOURS_PER_TICK` - When `progress >= 1`, spell is cast (cost deducted, damage dealt) - DPS = `damagePerCast * castsPerSecond` Damage calculation order: 1. Base spell damage 2. Skill bonuses (combatTrain, arcaneFury, etc.) 3. Upgrade effects (multipliers, bonuses) 4. Special effects (Overpower, Berserker, etc.) 5. Elemental modifiers (same element +25%, super effective +50%) ### 4. Crafting/Enchantment System Three-stage process: 1. **Design**: Select effects, takes time based on complexity 2. **Prepare**: Pay mana to prepare equipment, takes time 3. **Apply**: Apply design to equipment, costs mana per hour Equipment has **capacity** that limits total enchantment power. ### 5. Skill Evolution System Skills have 5 tiers of evolution: - At level 5: Choose 2 of 4 milestone upgrades - At level 10: Choose 2 more upgrades, then tier up - Each tier multiplies the skill's base effect by 10x ## Important Patterns ### Adding a New Effect 1. **Define in `enchantment-effects.ts`**: ```typescript my_new_effect: { id: 'my_new_effect', name: 'Effect Name', description: '+10% something', category: 'combat', baseCapacityCost: 30, maxStacks: 3, allowedEquipmentCategories: ['caster', 'hands'], effect: { type: 'multiplier', stat: 'attackSpeed', value: 1.10 } } ``` 2. **Add stat mapping in `effects.ts`** (if new stat): ```typescript // In computeEquipmentEffects() if (effect.stat === 'myNewStat') { bonuses.myNewStat = (bonuses.myNewStat || 0) + effect.value; } ``` 3. **Apply in game logic**: ```typescript const effects = getUnifiedEffects(state); damage *= effects.myNewStatMultiplier; ``` ### Adding a New Skill 1. **Define in `constants.ts` SKILLS_DEF** 2. **Add evolution path in `skill-evolution.ts`** 3. **Add prerequisite checks in `store.ts`** 4. **Update UI in `page.tsx`** ### Adding a New Spell 1. **Define in `constants.ts` SPELLS_DEF** 2. **Add spell enchantment in `enchantment-effects.ts`** 3. **Add research skill in `constants.ts`** 4. **Map research to effect in `EFFECT_RESEARCH_MAPPING`** ## Git Hooks (Husky) This project uses **Husky** to manage git hooks for automated checks and agent assistance: ### Pre-Commit Hook (`.husky/pre-commit`) Runs automatically before each commit: 1. **File Size Check**: Ensures no staged file exceeds 400 lines (improves AI agent readability) 2. **Project Structure Generation**: Updates `docs/project-structure.txt` with current tree (respects `.gitignore`) ### Post-Merge Hook (`.husky/post-merge`) Runs after merging branches: - Checks if `package.json` or `package-lock.json` changed - Automatically runs `npm install` to sync dependencies ### Implementation Files - Hook scripts: `.husky/` directory - File size check: `.husky/scripts/check-file-size.js` - Tree generator: `.husky/scripts/generate-project-tree.js` --- ## Common Pitfalls 1. **Forgetting to call `getUnifiedEffects()`**: Always use unified effects for stat calculations 2. **Direct stat modification**: Never modify stats directly; use effect system 3. **Missing tier multiplier**: Use `getTierMultiplier(skillId)` for tiered skills 4. **Ignoring special effects**: Check `hasSpecial(effects, SPECIAL_EFFECTS.X)` for special abilities ## Testing Guidelines - Run `bun run lint` after changes - Check dev server logs at `/home/z/my-project/dev.log` - Test with fresh game state (clear localStorage) ## Slice Pattern for Store Organization The store uses a **slice pattern** to organize related actions into separate files. This improves maintainability and makes the codebase more modular. ### Creating a New Slice 1. **Create the slice file** (e.g., `my-feature-slice.ts`): ```typescript // Define the actions interface export interface MyFeatureActions { doSomething: (param: string) => void; undoSomething: () => void; } // Create the slice factory export function createMyFeatureSlice( set: StoreApi['setState'], get: StoreApi['getState'] ): MyFeatureActions { return { doSomething: (param: string) => { set((state) => { // Update state }); }, undoSomething: () => { set((state) => { // Update state }); }, }; } ``` 2. **Add to main store** (`store.ts`): ```typescript import { createMyFeatureSlice, MyFeatureActions } from './my-feature-slice'; // Extend GameStore interface interface GameStore extends GameState, MyFeatureActions, /* other slices */ {} // Spread into store creation const useGameStore = create()( persist( (set, get) => ({ ...createMyFeatureSlice(set, get), // other slices and state }), // persist config ) ); ``` ### Existing Slices | Slice | File | Lines | Purpose | |-------|------|-------|----------| | Navigation | `navigation-slice.ts` | ~75 | Floor navigation (setClimbDirection, changeFloor) | | Study | `study-slice.ts` | ~210 | Study system (startStudyingSkill, startStudyingSpell, cancelStudy) | | Crafting | `crafting-slice.ts` | ~1100 | Equipment/enchantment (createEquipmentInstance, startDesigningEnchantment) | | Familiar | `familiar-slice.ts` | N/A | Familiar system - **File not found in current codebase** | ## File Size Guidelines ### Current File Sizes (After Task 2) | File | Lines | Size (bytes) | Notes | |------|-------|--------------|-------| | `store.ts` | ~2812 | ~103KB | Core state + tick logic, crafting-slice extracted | | `page.tsx` | ~548 | ~22KB | Main UI (heavily reduced through component extraction) | | `crafting-slice.ts` | ~1100 | ~35KB | Equipment/enchantment logic (extracted from store.ts) | | `skill-evolution.ts` | ~3400 | ~120KB | Skill tier progression paths | | `study-slice.ts` | ~210 | ~8KB | Study system actions | | `navigation-slice.ts` | ~75 | ~3KB | Navigation actions | | `computed-stats.ts` | ~12 | ~1KB | Extracted utility functions (some moved to slices) | | `components/game/tabs/*.tsx` | ~3000 | ~95KB | Tab-specific components (SpireTab, CraftingTab, etc.) | ### Guidelines - Keep `page.tsx` under 600 lines by extracting to components (ActionButtons, ManaDisplay, tabs, etc.) - Keep `store.ts` under 3000 lines by extracting to slices (navigation, study, crafting, familiar) - Extract computed stats and utility functions to appropriate slices or utils when >100 lines - Use barrel exports (`index.ts`) for clean imports - Follow the slice pattern for store organization (see below) - **After Task 2**: `page.tsx` reduced from ~2554 to ~548 lines (78% reduction) - **After Task 2**: `store.ts` increased due to crafting-slice integration, but better organized ### Automated File Size Check A pre-commit hook automatically checks all staged files. Files exceeding **400 lines** will be rejected. The hook runs via Husky and uses `.husky/scripts/check-file-size.js`. If your file is too large, refactor it into smaller modules before committing. --- ## 🚫 BANNED CONTENT - NEVER ADD THESE ### Lifesteal and Healing are BANNED **DO NOT add lifesteal or healing mechanics to player abilities.** This includes: - `lifesteal` spell effects - `heal` or `regeneration` abilities for the player - Any mechanic that restores player HP or mana based on damage dealt - Life-stealing weapons or enchantments **Rationale**: The game's core design is that the player cannot take damage - only floors can. Healing/lifesteal mechanics are unnecessary and would create confusing gameplay. ### Banned Mana Types The following mana types have been **removed** and should **never be re-added**: - `life` - Healing/lifesteal themed (banned) - `blood` - Life + Water compound (banned due to lifesteal theme) - `wood` - Life + Earth compound (banned due to life connection) - `mental` - Mind/psionic themed (removed for design consistency) - `force` - Telekinetic themed (removed for design consistency) --- ## 🔮 Mana Types Overview ### Base Mana Types (7) | Element | Symbol | Color | Theme | |---------|--------|-------|-------| | Fire | 🔥 | #FF6B35 | Destruction, burn damage | | Water | 💧 | #4ECDC4 | Flow, freeze effects | | Air | 🌬️ | #00D4FF | Speed, wind damage | | Earth | ⛰️ | #F4A261 | Stability, armor pierce | | Light | ☀️ | #FFD700 | Radiance, holy damage | | Dark | 🌑 | #9B59B6 | Shadows, void damage | | Death | 💀 | #778CA3 | Decay, rot damage | ### Utility Mana Types (1) | Element | Symbol | Color | Theme | |---------|--------|-------|-------| | Transference | 🔗 | #1ABC9C | Mana transfer, Enchanter attunement | ### Compound Mana Types (3) | Element | Recipe | Theme | |---------|--------|-------| | Metal | Fire + Earth | Armor piercing, forged weapons | | Sand | Earth + Water | AOE damage, desert winds | | Lightning | Fire + Air | Fast damage, armor pierce, chain effects | ### Exotic Mana Types (3) | Element | Recipe | Theme | |---------|--------|-------| | Crystal | Sand + Sand + Light | Prismatic, high damage | | Stellar | Fire + Fire + Light | Cosmic, ultimate fire/light | | Void | Dark + Dark + Death | Oblivion, ultimate dark/death | ### Mana Type Hierarchy ``` Base Elements (7) → Compound (3) → Exotic (3) ↓ Utility (1) ← Special attunement-based ```