7.5 KiB
Mana Loop - Project Architecture Guide
This document provides a comprehensive overview of the project architecture for AI agents working on this codebase.
⚠️ MANDATORY GIT WORKFLOW - MUST BE FOLLOWED
Before starting ANY work, you MUST:
-
Pull the latest changes:
cd /home/z/my-project && git pull origin master -
Do your task - Make all necessary code changes
-
Before finishing, commit and push:
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
- Mana Gathering: Click or auto-generate mana over time
- Studying: Spend mana to learn skills and spells
- Combat: Climb the Spire, defeat guardians, sign pacts
- Crafting: Enchant equipment with spell effects
- Prestige: Reset progress for permanent bonuses (Insight)
Directory Structure
src/
├── app/
│ ├── page.tsx # Main game UI (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
│ └── tabs/ # Tab-specific components
│ ├── CraftingTab.tsx
│ ├── LabTab.tsx
│ ├── SpellsTab.tsx
│ └── SpireTab.tsx
└── lib/
├── game/
│ ├── store.ts # Zustand store (state + 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
│ ├── crafting-slice.ts # Equipment/enchantment logic
│ ├── 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 single Zustand store with the following key slices:
interface GameState {
// Time
day: number;
hour: number;
paused: boolean;
// Mana
rawMana: number;
elements: Record<string, ElementState>;
// Combat
currentFloor: number;
floorHP: number;
activeSpell: string;
castProgress: number;
// Progression
skills: Record<string, number>;
spells: Record<string, SpellState>;
skillUpgrades: Record<string, string[]>;
skillTiers: Record<string, number>;
// Equipment
equipmentInstances: Record<string, EquipmentInstance>;
equippedInstances: Record<string, string | null>;
enchantmentDesigns: EnchantmentDesign[];
// Prestige
insight: number;
prestigeUpgrades: Record<string, number>;
signedPacts: number[];
}
2. Effect System (effects.ts)
CRITICAL: All stat modifications flow through the unified effect system.
// 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<string>, // Special effect IDs
}
When adding new stats:
- Add to
ComputedEffectsinterface inupgrade-effects.ts - Add mapping in
computeEquipmentEffects()ineffects.ts - 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:
- Base spell damage
- Skill bonuses (combatTrain, arcaneFury, etc.)
- Upgrade effects (multipliers, bonuses)
- Special effects (Overpower, Berserker, etc.)
- Elemental modifiers (same element +25%, super effective +50%)
4. Crafting/Enchantment System
Three-stage process:
- Design: Select effects, takes time based on complexity
- Prepare: Pay mana to prepare equipment, takes time
- 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
- Define in
enchantment-effects.ts:
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 }
}
- Add stat mapping in
effects.ts(if new stat):
// In computeEquipmentEffects()
if (effect.stat === 'myNewStat') {
bonuses.myNewStat = (bonuses.myNewStat || 0) + effect.value;
}
- Apply in game logic:
const effects = getUnifiedEffects(state);
damage *= effects.myNewStatMultiplier;
Adding a New Skill
- Define in
constants.tsSKILLS_DEF - Add evolution path in
skill-evolution.ts - Add prerequisite checks in
store.ts - Update UI in
page.tsx
Adding a New Spell
- Define in
constants.tsSPELLS_DEF - Add spell enchantment in
enchantment-effects.ts - Add research skill in
constants.ts - Map research to effect in
EFFECT_RESEARCH_MAPPING
Common Pitfalls
- Forgetting to call
getUnifiedEffects(): Always use unified effects for stat calculations - Direct stat modification: Never modify stats directly; use effect system
- Missing tier multiplier: Use
getTierMultiplier(skillId)for tiered skills - Ignoring special effects: Check
hasSpecial(effects, SPECIAL_EFFECTS.X)for special abilities
Testing Guidelines
- Run
bun run lintafter changes - Check dev server logs at
/home/z/my-project/dev.log - Test with fresh game state (clear localStorage)
File Size Guidelines
- Keep
page.tsxunder 2000 lines by extracting to tab components - Keep store functions focused; extract to helper files when >50 lines
- Use barrel exports (
index.ts) for clean imports