Files
Mana-Loop/AGENTS.md
Z User 3b2e89db74 pack
2026-03-25 15:05:12 +00:00

6.8 KiB

Mana Loop - Project Architecture Guide

This document provides a comprehensive overview of the project architecture for AI agents working on this codebase.

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 (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:

  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:
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 }
}
  1. Add stat mapping in effects.ts (if new stat):
// In computeEquipmentEffects()
if (effect.stat === 'myNewStat') {
  bonuses.myNewStat = (bonuses.myNewStat || 0) + effect.value;
}
  1. Apply in game logic:
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)

File Size Guidelines

  • Keep page.tsx under 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