# 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 (~1700 lines, single page application) │ ├── 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 # Main action buttons (Meditate, Climb, Study, etc.) │ ├── 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 │ ├── index.ts # Tab component exports │ ├── CraftingTab.tsx # Enchantment crafting UI │ ├── LabTab.tsx # Skill upgrade and lab features │ ├── SpellsTab.tsx # Spell management and equipment spells │ └── SpireTab.tsx # Combat and spire climbing └── lib/ ├── game/ │ ├── store.ts # Zustand store (~1650 lines, main state + tick logic) │ ├── computed-stats.ts # Computed stats functions (extracted utilities) │ ├── navigation-slice.ts # Floor navigation actions (setClimbDirection, changeFloor) │ ├── study-slice.ts # Study system actions (startStudying*, cancelStudy) │ ├── crafting-slice.ts # Equipment/enchantment logic │ ├── 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 │ ├── 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) ``` ## Key Systems ### 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 - **Navigation Slice** (`navigation-slice.ts`): Floor navigation (setClimbDirection, changeFloor) - **Study Slice** (`study-slice.ts`): Study system (startStudyingSkill, startStudyingSpell, cancelStudy) - **Crafting Slice** (`crafting-slice.ts`): Equipment/enchantment (createEquipmentInstance, startDesigningEnchantment) - **Familiar Slice** (`familiar-slice.ts`): Familiar system (addFamiliar, removeFamiliar) #### 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`** ## 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 | Purpose | |-------|------|---------| | Navigation | `navigation-slice.ts` | Floor navigation (setClimbDirection, changeFloor) | | Study | `study-slice.ts` | Study system (startStudyingSkill, startStudyingSpell, cancelStudy) | | Crafting | `crafting-slice.ts` | Equipment/enchantment (createEquipmentInstance, startDesigningEnchantment) | | Familiar | `familiar-slice.ts` | Familiar system (addFamiliar, removeFamiliar) | ## File Size Guidelines ### Current File Sizes (After Refactoring) | File | Lines | Notes | |------|-------|-------| | `store.ts` | ~1650 | Core state + tick logic (reduced from 2138, 23% reduction) | | `page.tsx` | ~1695 | Main UI (reduced from 2554, 34% reduction) | | `computed-stats.ts` | ~200 | Extracted utility functions | | `navigation-slice.ts` | ~50 | Navigation actions | | `study-slice.ts` | ~100 | Study system actions | ### Guidelines - Keep `page.tsx` under 2000 lines by extracting to components (ActionButtons, ManaDisplay, etc.) - Keep `store.ts` under 1800 lines by extracting to slices (navigation, study, crafting, familiar) - Extract computed stats and utility functions to `computed-stats.ts` when >50 lines - Use barrel exports (`index.ts`) for clean imports - Follow the slice pattern for store organization (see below)