18 KiB
Executable File
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:
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:
-
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 (~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.mdupdate_game_briefing_context.md- Context for updating GAME_BRIEFING.mdupdate_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()
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
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:
- File Size Check: Ensures no staged file exceeds 400 lines (improves AI agent readability)
- Project Structure Generation: Updates
docs/project-structure.txtwith current tree (respects.gitignore)
Post-Merge Hook (.husky/post-merge)
Runs after merging branches:
- Checks if
package.jsonorpackage-lock.jsonchanged - Automatically runs
npm installto 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
- 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)
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
- Create the slice file (e.g.,
my-feature-slice.ts):
// Define the actions interface
export interface MyFeatureActions {
doSomething: (param: string) => void;
undoSomething: () => void;
}
// Create the slice factory
export function createMyFeatureSlice(
set: StoreApi<GameStore>['setState'],
get: StoreApi<GameStore>['getState']
): MyFeatureActions {
return {
doSomething: (param: string) => {
set((state) => {
// Update state
});
},
undoSomething: () => {
set((state) => {
// Update state
});
},
};
}
- Add to main store (
store.ts):
import { createMyFeatureSlice, MyFeatureActions } from './my-feature-slice';
// Extend GameStore interface
interface GameStore extends GameState, MyFeatureActions, /* other slices */ {}
// Spread into store creation
const useGameStore = create<GameStore>()(
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.tsxunder 600 lines by extracting to components (ActionButtons, ManaDisplay, tabs, etc.) - Keep
store.tsunder 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.tsxreduced from ~2554 to ~548 lines (78% reduction) - After Task 2:
store.tsincreased 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:
lifestealspell effectshealorregenerationabilities 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