Back to Game

Spellforge Arena - Game Design Guide

Game Concept

# Spellforge Arena ## Theme You are a battle mage competing in the Spellforge Arena — a magical combat pit where wizards duel by crafting spells in real-time. The twist: you don't just cast pre-made spells. You COMBINE elemental runes during combat to create spell combinations, then send your constructed spells to battle automated guardians and rival mages. The arena is alive with elemental energy, and your spell combinations determine not just damage but battlefield control. ## Visual Game World The Canvas shows a top-down arena with a magical rune circle at the bottom where the player assembles spells. The center of the arena displays your current active spell (a glowing combination of elemental icons) flying toward enemies. Enemies spawn from the top and move toward your rune circle — if they reach it, you take damage and lose mana. The background is a dark stone arena floor with glowing magical pentagram patterns that pulse with your current dominant element. Elemental particles drift across the screen — embers for fire, sparkles for arcane, droplets for water. When spells hit enemies, there's visual feedback: explosions, freezing effects, lightning arcs. ## Player Interaction The player interacts DIRECTLY with the Canvas through rune slotting and spell targeting: 1. **Click Rune Slots**: At the bottom of the Canvas is a 3-slot spell builder. Clicking each slot cycles through elemental runes (Fire, Ice, Arcane, Void). The player physically sees their spell assembling as they click — a Fire rune adds orange glow, Ice adds blue crystals, etc. 2. **Cast Spell**: A large CAST button on the Canvas launches the constructed spell. The spell travels visibly from the rune circle toward the target. The player can aim by clicking on the Canvas — the spell flies toward where they clicked. 3. **Target Specific Enemies**: Click on any enemy to mark it as the target for your next spell. A reticle appears around the targeted enemy, and your spells will home toward it. 4. **Elemental Overdrive**: When your elemental charge meter fills (visible on Canvas as a glowing bar), click it to enter Overdrive mode — your next spell becomes a triple-strength version with visual aura effects. 5. **Rearrange Rune Order**: Drag runes between slots to change spell behavior. Fire+Ice is different from Ice+Fire — order matters and creates different spell patterns visible on screen. ## Entity Types ### Guardian - **Sprite**: `knight` with color variant (steel gray armor, glowing eyes) - **Appearance**: Medium-sized armored figure with a sword, moves with determined tread - **Behavior**: Spawns at top of screen, marches steadily toward player's rune circle. Has moderate HP, drops iron shards on death - **Interaction**: Player targets guardians with spells. Different spell combinations have different effectiveness (Fire does bonus damage, Ice slows them) ### Wisp - **Sprite**: `ghost` with color variant (cyan/white glow) - **Appearance**: Small, floating, translucent entity that drifts erratically - **Behavior**: Moves quickly in zigzag patterns toward player. Low HP but hard to hit due to movement. Drops mana fragments - **Interaction**: Arcane spells home in on wisps automatically. Other spell types require manual aiming ### Golem - **Sprite**: `slime` with scale 2.0x and brown/gray color variant - **Appearance**: Large, bulky, slow-moving creature that looms ominously - **Behavior**: Very slow but massive HP. Takes up significant space on screen. Drops rare crystal shards - **Interaction**: Void spells penetrate golems for full damage. Physical spell projectiles only deal partial damage ### Spell Projectile - **Sprite**: `fireball` with procedural color based on elemental composition - **Appearance**: Glowing orb with trailing particles. Color indicates element (orange=Fire, blue=Ice, purple=Arcane, black=Void) - **Behavior**: Spawns from rune circle, travels toward target or click location. Speed varies by elemental mix - **Interaction**: Created by player, travels to enemies. Multiple projectiles can be on screen simultaneously with upgrades ### Element Sprite - **Sprite**: `spark` with procedural colors and sizes - **Appearance**: Small particle that appears near rune slots, drifts slowly, and despawns - **Behavior**: Spawns periodically based on current elemental affinity. Collectible by clicking or hovering near - **Interaction**: Clicking element sprites grants temporary elemental charge and small resource boosts ### Elite Champion - **Sprite**: `wizard` with red/purple color variant and slight scale increase (1.2x) - **Appearance**: Robed figure with glowing staff, moves with purpose - **Behavior**: Appears every 60 seconds. Has special abilities (summons minions, fires counter-spells). Drops champion essence - **Interaction**: Requires strategic spell combinations. Weak to specific element that rotates each wave ## Core Loop ### Second-to-Second (ACTIVE GAMEPLAY) - The player watches enemies spawn and move toward their rune circle - They click rune slots to build spell combinations (Fire+Fire+Ice = Explosive Fireball that freezes) - They click CAST or press Space to launch the spell toward a target they've clicked on - Spells travel visibly across the Canvas, and the player sees them hit enemies - Enemies die with visual effects, drop resource sprites that the player can click to collect - The player decides moment-to-moment: fast weak spells or slow powerful ones? Target the dangerous golem or clear the fast wisps? ### Minute-to-Minute (STRATEGIC DECISIONS) - Between waves, the player purchases rune slot upgrades (4th slot, 5th slot) - They buy elemental mastery upgrades that change how spell combinations work - They check their resource stores and decide which elemental affinities to invest in - The Canvas gameplay changes: new spell combinations unlock, projectile speed increases, new enemy types appear ### Session-Level (META STRATEGY) - The player pursues an elemental specialization build (Fire-focused for burst damage, Ice for crowd control, Void for boss killing) - The arena evolves visually: their rune circle grows elaborate, background effects intensify, spell effects become more dramatic - The push toward prestige: they've unlocked most spell combinations, enemies are scaling faster than upgrades, they're ready to reset for permanent rune slots ## The 30-Second Gameplay Description A wisp drifts erratically from the top of the arena, zigzagging left and right. You click your first rune slot twice, cycling to Fire, then click the second slot to set it to Ice. A Guardian and two Wisps have spawned — the Guardian is moving straight down the center while the Wisps weave toward the edges. You click on the Guardian to target it, then hit CAST. An orange-blue streak erupts from your rune circle, trailing mixed particles, and slams into the Guardian. The Guardian flashes white and stumbles backward, slowed by the ice component. You quickly cycle your slots to Arcane-Arcane-Arcane, targeting a Wisp this time, and CAST. A purple bolt streaks out, curving mid-flight to home in on the Wisp, popping it instantly. An elemental spark drifts near your rune circle — you click it and your mana bar pulses. The Guardian has recovered and is closing in. You have seconds to craft the right combination. ## Currencies ### Mana - **Role**: Primary currency - **Earned by**: Killing enemies drops mana fragments that appear as blue sprites on Canvas. Click them to collect. Also regenerates slowly over time - **Spent on**: Casting spells (each rune combination costs mana), buying basic upgrades, unlocking new rune elements - **Feel**: The flow of battle. You're always balancing "cast now" vs "wait for more mana" — creates tension and rhythm ### Iron Shards - **Role**: Secondary currency / Upgrade material - **Earned by**: Guardians drop iron shards on death as gray crystal sprites. Also earned from elemental sprite clicks - **Spent on**: Permanent rune slot unlocks, elemental mastery upgrades, spell damage multipliers - **Feel**: Long-term progression. These are the "meat" of upgrades — you see them pile up and decide when to spend big ### Crystal Essence - **Role**: Prestige currency / Rare upgrades - **Earned by**: Elite Champions drop crystal essence (rare purple sprites), Golem boss kills grant bonus essence, can convert Iron Shards to Essence at poor rate - **Spent on**: Permanent rune slots that persist across prestige, elemental attunement bonuses, prestige currency storage upgrades - **Feel**: The precious reward. You see a purple drop and get excited — this is your long-term power ### Elemental Charge - **Role**: Temporary boost currency - **Earned by**: Casting spells of the same element builds charge (3 Fire spells in a row = Fire charge), clicking element sprites, killing enemies with their weakness element - **Spent on**: Overdrive mode (next spell is 3x power), temporary elemental effects (Fire charge = burning damage over time) - **Feel**: Combat momentum. You're building toward a big moment, then unleash it ### Currency Flow Mana → Spells → Enemy kills → Iron Shards → Upgrades → More efficient spells → More mana per cast Iron Shards → Convert → Crystal Essence (at 100:1 ratio) → Prestige upgrades → Bonus Iron Shard drop rate Elemental Charge → Overdrive → More kills → More Mana → Faster spell casting → Faster charge build ## Progression Hooks ### Early Game (0-5 minutes) - Hook: The first time you discover a spell combination (Fire+Ice = Explosive Freeze), enemies explode with satisfying visual feedback - Canvas interaction: Immediately clicking rune slots, casting spells, targeting enemies - "Aha" moment: Realizing rune ORDER matters — Fire+Ice is different from Ice+Fire ### Mid Game (5-15 minutes) - New systems: 4th rune slot unlocks, Elite Champions appear with elemental weaknesses shown on Canvas, elemental overdrive becomes available - Canvas expansion: More simultaneous projectiles, larger area of effect spells, new enemy types (Golems, Champions) - Strategy: Player must specialize — will they focus on one element or diversify? ### Late Game (15-30 minutes) - Final push: All 5 rune slots unlocked, mastery of spell combinations, prestige approaching - Visual complexity: Arena is filled with projectiles, particle effects, multiple enemy types, elaborate rune circle animations - Challenge: Enemy spawn rate is intense, player must master spell economy and target priority ### Key Milestones 1. **First Spell Cast**: Cast any spell — unlocks the core mechanic 2. **Combination Discovery**: Discover first spell combo — shows rune slot count increases 3. **Rune Slot 4**: Unlock 4th rune slot — spell complexity explodes 4. **First Elite Champion**: Elite appears with health bar and weakness indicator 5. **Elemental Overdrive**: Charge meter fills and becomes clickable 6. **Rune Slot 5**: Final rune slot — maximum spell complexity 7. **Golem Invasion**: First Golem boss — requires strategy to defeat 8. **Prestige Available**: Defeat champion wave 10 — prestige unlocks ## Meaningful Choices - **Choice 1: Elemental Specialization vs. Versatility** - Specialize in one element (Fire focus = high burst damage, but vulnerable to water-resistant enemies). Visually, your arena background, rune circle, and spell effects all shift to that element. The player becomes a master of that element but struggles with enemies resistant to it. - Versatility (balanced elements = always have effective spell, but never maximum damage). Visuals are mixed and colorful. Player can handle any enemy but lacks peak power. - Changes what the player DOES: Specialist cycles runes less often (stays in their element), Versatile player constantly adapts rune combinations - **Choice 2: Rune Slot Configuration** - More slots (5 slots = complex spells with multiple effects) OR fewer slots with mastery (3 slots but each rune is 2x powerful) - More slots: Player engages in complex rune-cycling, creating elaborate multi-element spells. Canvas shows many projectiles with varied effects - Fewer slots: Player casts simpler spells more frequently. Faster combat rhythm, less planning - Changes Canvas gameplay: More slots = spectacular but slow combos, Fewer slots = rapid-fire casting ## Prestige Concept - **Trigger**: Defeat Champion Wave 15 and reach Arena Tier 10 - **What resets**: Mana, Iron Shards, rune slot count, elemental mastery levels, current wave, arena tier - **What persists**: Crystal Essence balance, permanent rune slots (purchased with Crystal Essence), elemental attunement bonuses, prestige tier - **Prestige currency**: Crystal Essence (earned during run + bonus at prestige based on max wave reached) - **Acceleration**: Start with +1 permanent rune slot (cap of 3), +10% damage to chosen element, faster mana regeneration. Run 2 involves discovering new spell combinations earlier, fighting stronger enemies from the start, and reaching higher waves faster - **Visual transformation**: Arena background becomes more ornate with each prestige tier. Rune circle gains intricate glowing patterns. Spell projectiles gain trail effects. The arena visibly transforms from a crude stone circle to an elaborate magical sanctum ## Controls Display - Left Click Rune Slot → Cycle element (Fire/Ice/Arcane/Void) - Left Click Arena → Target spell location - SPACE or Click CAST → Launch crafted spell - Click Resource Sprites → Collect mana/iron/crystal - Click Overdrive Bar → Activate elemental overdrive ## Getting Started Tutorial • Click the rune slots at the bottom to craft your spell — combine elements for different effects • Press SPACE or click CAST to launch your spell at enemies — stop them from reaching your rune circle • Collect dropped resources by clicking them, and use mana to cast spells, iron to buy upgrades • Discover spell combinations and survive as many waves as possible to unlock prestige ## Unique Selling Point The core innovation is **real-time rune slotting** — you're not just clicking a cast button, you're actively assembling spell combinations during combat. The order and composition of your 3-5 rune slots creates actual strategic depth visible on screen, with immediate feedback in how your spells fly, hit, and affect enemies. It's a puzzle game where the puzzle pieces change every second. ## Visual Direction Color palette: Deep purple and midnight blue background (mystical arena feel) with bright elemental accents — orange fire, cyan ice, violet arcane, black void with white rim-lighting. The arena feels like an underground mystical chamber, with stone textures and glowing magical lines. As the game progresses, the background becomes more elaborate with magical symbols and light rays. Spell effects are juicy with particles, screenshake on big hits, and color-coded explosions. ## Technical Scope Check Implementable with the sprite framework: - Fireball sprite can be color-varianted for all spell types using ProceduralSprite - Knight, Ghost, Slime (scaled), Wizard (colored) cover all enemy types - Spark sprite for element collectibles - Canvas interactions are simple click detection on zones (rune slots, arena click areas) - Spell projectile system is straightforward array of objects with position, velocity, element properties - Enemy pathfinding is simple "move toward bottom center" with minimal collision - UI elements are HTML overlay, not Canvas Complex mechanics to simplify if needed: - Start with 3 rune slots, expand to 4-5 - Implement 4 base elements first (Fire, Ice, Arcane, Void) - Elite special abilities can be simple (just stat variations) initially - No need for complex spell physics — simple projectiles and collision detection

Currencies

{
  "gameName": "Spellforge Arena",
  "currencies": {
    "mana": {
      "displayName": "Mana",
      "icon": "💧",
      "startingAmount": 20,
      "cap": 100,
      "capPerUpgrade": 20,
      "decimals": 0,
      "suffixes": [],
      "persistsOnPrestige": false,
      "regenRate": 2,
      "regenPerMastery": 1
    },
    "ironShards": {
      "displayName": "Iron Shards",
      "icon": "⚙️",
      "startingAmount": 0,
      "cap": null,
      "decimals": 0,
      "suffixes": [
        "K",
        "M",
        "B"
      ],
      "persistsOnPrestige": false
    },
    "crystalEssence": {
      "displayName": "Crystal Essence",
      "icon": "💎",
      "startingAmount": 0,
      "cap": null,
      "decimals": 0,
      "suffixes": [
        "K",
        "M"
      ],
      "persistsOnPrestige": true
    },
    "elementalCharge": {
      "displayName": "Elemental Charge",
      "icon": "⚡",
      "startingAmount": 0,
      "cap": 100,
      "decimals": 0,
      "suffixes": [],
      "persistsOnPrestige": false,
      "decayRate": 1,
      "decayInterval": 3000
    }
  },
  "currencySources": {
    "wispKillMana": {
      "currency": "mana",
      "baseReward": 3,
      "formula": "baseReward",
      "collectible": "manaFragment",
      "chance": 1
    },
    "guardianKillMana": {
      "currency": "mana",
      "baseReward": 2,
      "formula": "baseReward",
      "collectible": "manaFragment",
      "chance": 1
    },
    "guardianKillIron": {
      "currency": "ironShards",
      "baseReward": 5,
      "formula": "baseReward * (1 + 0.05 * waveNumber)",
      "collectible": "ironShard",
      "chance": 1
    },
    "golemKillIron": {
      "currency": "ironShards",
      "baseReward": 15,
      "formula": "baseReward * (1 + 0.05 * waveNumber)",
      "collectible": "ironShard",
      "chance": 1
    },
    "golemKillEssence": {
      "currency": "crystalEssence",
      "baseReward": 1,
      "formula": "baseReward",
      "collectible": "crystalEssence",
      "chance": 0.3
    },
    "championKillIron": {
      "currency": "ironShards",
      "baseReward": 20,
      "formula": "baseReward * (1 + 0.05 * waveNumber)",
      "collectible": "ironShard",
      "chance": 1
    },
    "championKillEssence": {
      "currency": "crystalEssence",
      "baseReward": 3,
      "formula": "baseReward + Math.floor(waveNumber / 5)",
      "collectible": "crystalEssence",
      "chance": 0.6
    },
    "waveCompleteMana": {
      "currency": "mana",
      "baseReward": 10,
      "formula": "baseReward * waveNumber",
      "direct": true
    },
    "elementSpriteCharge": {
      "currency": "elementalCharge",
      "baseReward": 2,
      "formula": "baseReward",
      "collectible": "elementSprite",
      "chance": 1
    },
    "elementSpriteMana": {
      "currency": "mana",
      "baseReward": 1,
      "formula": "baseReward",
      "collectible": "elementSprite",
      "chance": 1
    },
    "elementSpriteIron": {
      "currency": "ironShards",
      "baseReward": 1,
      "formula": "baseReward",
      "collectible": "elementSprite",
      "chance": 0.2
    },
    "sameElementSpellChain": {
      "currency": "elementalCharge",
      "baseReward": 10,
      "formula": "baseReward * (1 + 0.1 * chainLength)",
      "direct": true,
      "condition": "lastSpellElement === currentSpellElement"
    },
    "enemyWeaknessKill": {
      "currency": "elementalCharge",
      "baseReward": 5,
      "formula": "baseReward",
      "direct": true,
      "condition": "spellElement === enemy.weakness"
    },
    "prestigeEssence": {
      "currency": "crystalEssence",
      "formula": "maxWaveReached * 0.5 + eliteChampionsKilled * 2",
      "direct": true
    }
  },
  "collectibles": {
    "manaFragment": {
      "sprite": "spark",
      "color": "#00ffff",
      "scale": 1.2,
      "lifetime": 8,
      "collectRadius": 20,
      "bobAmplitude": 2,
      "bobSpeed": 2,
      "spawnAnimation": "popIn",
      "spawnAnimationDuration": 200,
      "collectAnimation": "burst",
      "particleCount": 5,
      "particleColor": "#00ffff",
      "value": 3,
      "sound": "mana_collect",
      "magnetRadius": 100,
      "magnetStrength": 200,
      "showsValue": true
    },
    "ironShard": {
      "sprite": "spark",
      "color": "#808080",
      "scale": 1.5,
      "lifetime": 10,
      "collectRadius": 22,
      "bobAmplitude": 2,
      "bobSpeed": 1.5,
      "spawnAnimation": "popIn",
      "spawnAnimationDuration": 250,
      "collectAnimation": "burst",
      "particleCount": 7,
      "particleColor": "#a0a0a0",
      "value": 5,
      "sound": "iron_collect",
      "magnetRadius": 120,
      "magnetStrength": 180,
      "showsValue": true,
      "metallic": true
    },
    "ironShardLarge": {
      "extends": "ironShard",
      "scale": 2,
      "value": 15,
      "particleCount": 10
    },
    "crystalEssence": {
      "sprite": "spark",
      "color": "#9932cc",
      "scale": 2,
      "lifetime": 15,
      "collectRadius": 25,
      "bobAmplitude": 3,
      "bobSpeed": 1,
      "spawnAnimation": "popIn",
      "spawnAnimationDuration": 400,
      "collectAnimation": "burst",
      "particleCount": 15,
      "particleColor": "#b34dff",
      "value": 1,
      "sound": "essence_collect",
      "magnetRadius": 150,
      "magnetStrength": 250,
      "showsValue": true,
      "glow": true,
      "neverDespawnOnScreen": true,
      "celebrate": true
    },
    "elementSprite": {
      "sprite": "spark",
      "color": "varies",
      "scale": 1,
      "lifetime": 6,
      "collectRadius": 18,
      "bobAmplitude": 2,
      "bobSpeed": 2.5,
      "spawnAnimation": "fadeIn",
      "spawnAnimationDuration": 300,
      "collectAnimation": "burst",
      "particleCount": 3,
      "particleColor": "varies",
      "value": 2,
      "sound": "element_collect",
      "magnetRadius": 80,
      "magnetStrength": 150,
      "showsValue": true,
      "orbit": true,
      "orbitRadius": 60,
      "orbitSpeed": 1
    }
  },
  "upgradeCosts": {
    "runeSlot4": {
      "baseCost": 100,
      "costMultiplier": 1,
      "currency": "ironShards",
      "requires": "waveNumber >= 5"
    },
    "runeSlot5": {
      "baseCost": 500,
      "costMultiplier": 1,
      "currency": "ironShards",
      "requires": "waveNumber >= 10 && runeSlot4"
    },
    "fireMastery": {
      "baseCost": 30,
      "costMultiplier": 1.3,
      "currency": "ironShards",
      "maxLevel": 10,
      "effect": {
        "type": "damage",
        "element": "fire",
        "perLevel": 0.1
      }
    },
    "iceMastery": {
      "baseCost": 30,
      "costMultiplier": 1.3,
      "currency": "ironShards",
      "maxLevel": 10,
      "effect": {
        "type": "damage",
        "element": "ice",
        "perLevel": 0.1
      }
    },
    "arcaneMastery": {
      "baseCost": 30,
      "costMultiplier": 1.3,
      "currency": "ironShards",
      "maxLevel": 10,
      "effect": {
        "type": "damage",
        "element": "arcane",
        "perLevel": 0.1
      }
    },
    "voidMastery": {
      "baseCost": 30,
      "costMultiplier": 1.3,
      "currency": "ironShards",
      "maxLevel": 10,
      "effect": {
        "type": "damage",
        "element": "void",
        "perLevel": 0.1
      }
    },
    "spellDamage": {
      "baseCost": 50,
      "costMultiplier": 1.2,
      "currency": "ironShards",
      "maxLevel": 15,
      "effect": {
        "type": "damage",
        "element": "all",
        "perLevel": 0.05
      }
    },
    "manaMastery": {
      "baseCost": 30,
      "costMultiplier": 1.3,
      "currency": "mana",
      "maxLevel": 5,
      "effect": {
        "type": "regen",
        "perLevel": 1
      }
    },
    "unlockElement": {
      "baseCost": 25,
      "costMultiplier": 1,
      "currency": "mana",
      "oneTime": true,
      "requires": "!elementUnlocked"
    },
    "permanentRuneSlot": {
      "baseCost": 50,
      "costMultiplier": 1.5,
      "currency": "crystalEssence",
      "maxPurchases": 2,
      "effect": {
        "type": "permanent",
        "property": "startingRuneSlots",
        "value": 1
      },
      "persists": true
    },
    "elementalAttunement": {
      "baseCost": 100,
      "costMultiplier": 1.3,
      "currency": "crystalEssence",
      "maxLevel": 5,
      "effect": {
        "type": "damage",
        "element": "chosen",
        "perLevel": 0.1
      },
      "persists": true
    },
    "manaCapUpgrade": {
      "baseCost": 75,
      "costMultiplier": 1.3,
      "currency": "crystalEssence",
      "maxPurchases": 5,
      "effect": {
        "type": "cap",
        "currency": "mana",
        "value": 20
      },
      "persists": true
    },
    "startingManaUpgrade": {
      "baseCost": 60,
      "costMultiplier": 1.4,
      "currency": "crystalEssence",
      "maxPurchases": 3,
      "effect": {
        "type": "startingAmount",
        "currency": "mana",
        "value": 10
      },
      "persists": true
    }
  },
  "spellCosts": {
    "base": 3,
    "perSlot": 1,
    "formula": "baseCost + (runeSlots - 3) * perSlot",
    "elementCosts": {
      "fire": 1,
      "ice": 1,
      "arcane": 1.2,
      "void": 1.5
    }
  },
  "conversions": {
    "ironToEssence": {
      "input": {
        "currency": "ironShards",
        "amount": 100
      },
      "output": {
        "currency": "crystalEssence",
        "amount": 1
      },
      "unlockCondition": "true",
      "cooldown": 0,
      "oneWay": true
    }
  },
  "balanceTargets": {
    "firstSpellCost": 3,
    "firstUpgradeAffordable": 10,
    "firstRuneSlotUnlockTime": 240,
    "firstEssenceDropTime": 300,
    "prestigeTime": 1500
  },
  "formulas": {
    "spellCost": "baseCost + (runeSlots - 3) * perSlot",
    "upgradeCost": "baseCost * costMultiplier^level",
    "enemyKillReward": "baseReward * (1 + 0.05 * waveNumber)",
    "waveCompleteBonus": "10 * waveNumber",
    "manaRegen": "2 + manaMasteryLevel",
    "manaCap": "100 + (manaCapLevel * 20)",
    "elementalChargeFromChain": "10 * (1 + 0.1 * chainLength)",
    "elementalChargeDecay": "-1 per 3 seconds",
    "conversion": "floor(ironShards / 100) → essence",
    "prestigeEssenceBonus": "maxWave * 0.5 + eliteKills * 2",
    "masteryCost": "30 * 1.3^level",
    "spellDamageCost": "50 * 1.2^level"
  }
}

Currencies

# Spellforge Arena - Currency System Design ## Economy Flow Diagram ```mermaid flowchart LR subgraph "Sources (Gameplay Actions)" WispKill["Wisp Killed\n+3 Mana fragments"] GuardianKill["Guardian Killed\n+5 Iron Shards"] GolemKill["Golem Killed\n+15 Iron Shards\n+1 Crystal Essence"] ChampionKill["Elite Champion Killed\n+20 Iron Shards\n+3 Crystal Essence"] ElementSprite["Element Sprite Clicked\n+2 Elemental Charge\n+1 Mana fragment"] WaveComplete["Wave Complete\n+10 Mana per wave"] end subgraph "Sources (Passive)" ManaRegen["Mana Regen\nbaseRegen * masteryLevel/sec"] ChargeDecay["Elemental Charge Decay\n-1 per 3 seconds"] end subgraph "Currencies" Mana((Mana 💧\nPrimary\nstart: 20\nmax: 100 + upgrades)) IronShards((Iron Shards ⚙️\nSecondary\nstart: 0\nuncapped)) CrystalEssence((Crystal Essence 💎\nPrestige\nstart: 0\npersists)) ElementalCharge((Elemental Charge ⚡\nTemporary\nstart: 0\nmax: 100)) end subgraph "Sinks" CastSpell["Cast Spell\ncost: runeSlots * elementCost"] UnlockRuneSlot["Unlock Rune Slot\ncost: base * 1.5^slotIndex"] ElementalMastery["Elemental Mastery\ncost: base * 1.3^level"] SpellDamage["Spell Damage\ncost: base * 1.2^level"] ConvertToEssence["Convert to Essence\n100 Iron → 1 Essence"] Overdrive["Overdrive Mode\ncost: 50 Charge"] end WispKill --> Mana GuardianKill --> IronShards GolemKill --> IronShards GolemKill --> CrystalEssence ChampionKill --> IronShards ChampionKill --> CrystalEssence ElementSprite --> ElementalCharge ElementSprite --> Mana WaveComplete --> Mana ManaRegen --> Mana ChargeDecay --> ElementalCharge Mana --> CastSpell IronShards --> UnlockRuneSlot IronShards --> ElementalMastery IronShards --> SpellDamage IronShards --> ConvertToEssence ConvertToEssence --> CrystalEssence CrystalEssence -->|Permanent|RuneSlot CrystalEssence -->|Permanent|ElementalBonus ElementalCharge --> Overdrive Overdrive -->|3x damage|CastSpell ``` ## Currency Definitions Diagram ```mermaid graph TD subgraph "Mana 💧 [Primary Currency]" M_display["Display: 💧 Mana\n0 decimals\nMax: 100 + 20 per mastery"] M_earn["Earning:\nWisp kill: +3 Mana fragment (collect)\nGuardian kill: +2 Mana fragment\nWave complete: +10 * waveNumber\nPassive regen: 2 + masteryLevel/sec\nElement sprite click: +1 Mana"] M_spend["Spending:\nCast spell: runeSlotCount * elementCost\nUnlock element: 25 Mana once\nMana mastery: cost * 1.3^level"] M_inflation["Inflation Control:\nHard cap at 100 + upgrades\nSpell costs scale with rune slots\nPrestige reset to base"] end subgraph "Iron Shards ⚙️ [Secondary Currency]" I_display["Display: ⚙️ Iron\n0 decimals\nUncapped\nSuffixes: K/M"] I_earn["Earning:\nGuardian kill: +5 Iron shard (collect)\nGolem kill: +15 Iron shards\nElite Champion: +20 Iron shards\nElement sprite: +1 Iron (20% chance)"] I_spend["Spending:\nUnlock rune slot 4: 100 Iron\nUnlock rune slot 5: 500 Iron\nElemental mastery: 30 * 1.3^level\nSpell damage: 50 * 1.2^level"] I_inflation["Inflation Control:\nExponential upgrade costs\n100:1 conversion to Essence drains surplus\nPrestige reset to 0"] end subgraph "Crystal Essence 💎 [Prestige Currency]" C_display["Display: 💎 Essence\n0 decimals\nPersists across prestiges\nSuffixes: K/M"] C_earn["Earning:\nGolem boss kill: +1 Essence\nElite Champion kill: +3 Essence\nPrestige bonus: waveNumber * 0.5\nConversion: 100 Iron → 1 Essence"] C_spend["Spending:\n+1 Permanent rune slot: 50 Essence\nElemental attunement +10%: 100 Essence\nMana cap +20: 75 Essence\nStarting mana +10: 60 Essence"] C_inflation["Inflation Control:\nExpensive permanent upgrades\nCosts scale with purchase count\nNo cap - accumulation is slow"] end subgraph "Elemental Charge ⚡ [Temporary Boost Currency]" E_display["Display: ⚡ Charge\n0-100 scale\nDecays: -1 per 3 sec\nResets on prestige"] E_earn["Earning:\nSame-element spell chain: +10 per spell\nElement sprite click: +2 Charge\nEnemy weakness kill: +5 Charge\nOverdrive cooldown reset: +30 when full"] E_spend["Spending:\nOverdrive activation: 50 Charge\nEffect: next spell 3x damage + visual aura"] E_inflation["Inflation Control:\nHard cap at 100\nDecay prevents hoarding\nResets each combat session"] end ``` ## Conversion Rate Diagram ```mermaid flowchart LR IronShards["Iron Shards\n(100)"] -->|"100:1 ratio\nAlways available\nNo cooldown\nClick to convert"| CrystalEssence["Crystal Essence\n(1)"] Mana["Mana\n(50)"] & IronShards2["Iron Shards\n(25)"] -->|"Combined Spell Crafting\nHigh-tier spells\nUnlocked at: Wave 5"| HighTierSpell["Premium Spell\n(Unlocks new combo)"] ``` ## Pacing Timeline ```mermaid gantt title Currency Pacing (First 30 Minutes) dateFormat mm:ss axisFormat %M:%S section Mana Milestones First spell affordable (5 Mana) :milestone, 00:05, 0 First element unlock (25 Mana) :milestone, 00:45, 0 Mana mastery purchased (30 Mana) :milestone, 02:00, 0 Mid-game mana flow (1000+ total) :milestone, 12:00, 0 section Iron Shard Milestones First shard earned :milestone, 00:30, 0 Rune slot 4 unlock (100 Iron) :milestone, 04:00, 0 First mastery purchased (30 Iron) :milestone, 03:00, 0 Rune slot 5 unlock (500 Iron) :milestone, 15:00, 0 section Crystal Essence Milestones First Essence drop (Golem) :milestone, 05:00, 0 First permanent upgrade (50 Essence) :milestone, 20:00, 0 Prestige available (25+ Essence) :milestone, 25:00, 0 section Key Moments First spell cast :milestone, 00:05, 0 Element sprite discovery :milestone, 01:00, 0 Overdrive first use :milestone, 02:30, 0 Elite Champion appears :milestone, 03:00, 0 First Golem boss :milestone, 05:00, 0 Prestige recommended :milestone, 25:00, 0 ``` ## Upgrade Cost Curves ```mermaid graph LR subgraph "Rune Slot 4 Unlock" RS4_1["Base\nCost: 100 Iron\nUnlocks: 4th rune slot"] RS4_2["After 1 prestige\nCost: 80 Iron\nPermanent bonus: -20%"] end subgraph "Rune Slot 5 Unlock" RS5_1["Base\nCost: 500 Iron\nUnlocks: 5th rune slot\nRequires: Wave 10"] RS5_2["After 1 prestige\nCost: 400 Iron\nPermanent bonus: -20%"] end subgraph "Fire Mastery Leveling" FM1["Level 1\nCost: 30 Iron\nFire damage: +10%"] FM2["Level 5\nCost: 86 Iron\nFire damage: +50%"] FM3["Level 10\nCost: 392 Iron\nFire damage: +100%"] FM1 --> FM2 --> FM3 end subgraph "Spell Damage Upgrade" SD1["Level 1\nCost: 50 Iron\nAll spell damage: +5%"] SD2["Level 5\nCost: 124 Iron\nAll spell damage: +25%"] SD3["Level 10\nCost: 307 Iron\nAll spell damage: +50%"] SD1 --> SD2 --> SD3 end subgraph "Mana Cap Upgrade" MC1["Level 1\nCost: 75 Essence\nMana max: +20"] MC2["Level 3\nCost: 171 Essence\nMana max: +60"] MC1 --> MC2 end ``` ## Collectible Entity State Machines ### Mana Fragment ```mermaid stateDiagram-v2 [*] --> Spawning: Wisp/Guardian dies Spawning --> Active: spawn animation (200ms)\nscale 0 → 1 Active --> Collected: player clicks within 20px Active --> Expired: lifetime 8s exceeded Active --> Attracting: magnetism unlocked\nwithin 100px of player Attracting --> Collected: reaches player position Attracting --> Expired: lifetime exceeded Collected --> [*]: add Mana + floating "+3"\nparticle burst (blue) Expired --> [*]: fade out (300ms) note right of Active Visual: cyan bob animation, glow Clickable radius: 20px Shows "+3" on hover Drifts slowly downward Sprite: spark (cyan, scale 1.2) end note note right of Collected Triggers: currency.add('mana', 3) Triggers: floatingText("+3💧", cyan) Triggers: particle burst (5 blue sparks) Triggers: ui.update('mana') Sound: soft magical chime end note ``` ### Iron Shard ```mermaid stateDiagram-v2 [*] --> Spawning: Guardian/Golem/Champion dies Spawning --> Active: spawn animation (250ms)\nwith metallic flash Active --> Collected: player clicks within 22px Active --> Expired: lifetime 10s exceeded Active --> Attracting: magnetism unlocked\nwithin 120px Attracting --> Collected: reaches player Attracting --> Expired: lifetime exceeded Collected --> [*]: add Iron Shards + value\nfloating text Expired --> [*]: fade out (400ms) note right of Active Visual: gray crystal bob, metallic sheen Clickable radius: 22px Shows value on hover (5/15/20) Sprite: spark (gray, scale 1.5) Golem/Champion shards: larger (scale 2.0) end note note right of Collected Triggers: currency.add('ironShards', value) Triggers: floatingText("+{value}⚙️", silver) Triggers: particle burst (7 gray crystals) Triggers: ui.update('ironShards') Sound: metallic clink end note ``` ### Crystal Essence ```mermaid stateDiagram-v2 [*] --> Spawning: Golem/Champion dies (rare) Spawning --> Active: spawn animation (400ms)\nwith purple flash Active --> Collected: player clicks within 25px Active --> Expired: lifetime 15s exceeded Active --> Attracting: magnetism always active\nwithin 150px Attracting --> Collected: reaches player Attracting --> Expired: lifetime exceeded Collected --> [*]: add Crystal Essence + value\nmajor visual celebration Expired --> [*]: fade out (500ms)\nwith sad sound note right of Active Visual: purple glow, pulsing aura Clickable radius: 25px (generous) Shows "💎" on hover Sprite: spark (purple, scale 2.0) Has trail particle effect NEVER auto-despawns if on screen end note note right of Collected Triggers: currency.add('crystalEssence', value) Triggers: floatingText("+{value}💎", purple, large) Triggers: screen flash (purple tint) Triggers: particle burst (15 purple crystals) Triggers: ui.update('crystalEssence') Triggers: ui.celebrate() Sound: magical chime + echo end note ``` ### Element Sprite (Elemental Charge Source) ```mermaid stateDiagram-v2 [*] --> Spawning: periodic spawn\nevery 8-12 seconds Spawning --> Active: fade in (300ms) Active --> Collected: player clicks within 18px\nor hovers Active --> Expired: lifetime 6s exceeded Collected --> [*]: add Elemental Charge + bonuses Expired --> [*]: fade out (200ms) note right of Active Visual: colored spark, matches element Clickable radius: 18px Element colors: Fire(orange), Ice(cyan), Arcane(purple), Void(black) Orbits near rune circle Sprite: spark (element color, scale 1.0) end note note right of Collected Triggers: currency.add('elementalCharge', 2) Triggers: currency.add('mana', 1) Triggers: floatingText("+2⚡", element color) Triggers: particle burst (3 colored sparks) Triggers: ui.update('elementalCharge') Sound: elemental fizz end note ``` ## Currency Event Flow ### Enemy Kill → Resource Drop → Collection ```mermaid sequenceDiagram participant Canvas as Canvas (Game World) participant Entity as Entity System participant EventBus as EventBus participant Currency as CurrencyManager participant Collectible as Collectible System participant UI as HUD Display Canvas->>Entity: enemy.takeDamage(spellDamage) Entity->>Entity: hp -= spellDamage Entity->>Entity: hp <= 0 → die() Entity->>Canvas: death animation + particles Entity->>EventBus: emit('enemy-killed', {type, position, wave}) EventBus->>Collectible: spawnCollectible({type, position, value}) Note over Collectible: Determine drop type based on enemy:\n- Wisp: Mana fragment (+3)\n- Guardian: Iron shard (+5) + Mana (+2)\n- Golem: Iron shards (+15) + Essence (30%)\n- Champion: Iron shards (+20) + Essence (60%) Collectible->>Canvas: create sprite at position Canvas->>Canvas: spawn animation (200-400ms)\nstart bob animation Note over Canvas: Player clicks collectible\nwithin radius Canvas->>EventBus: emit('collectible-collected', {type, value, position}) EventBus->>Currency: currency.add(type, value) Currency->>Currency: validate + add to balance Currency->>EventBus: emit('currency-changed', {type, newBalance}) EventBus->>UI: floatingText("+{value}{icon}", position, color) EventBus->>UI: updateDisplay(type) EventBus->>Canvas: particle burst(position, count, color) EventBus->>Canvas: playSound('collect') UI->>UI: count-up animation (200ms)\nupdate displayed value ``` ### Spell Cast → Mana Spend → Effect ```mermaid sequenceDiagram participant Player as Player Input participant Rune as Rune System participant Currency as CurrencyManager participant Spell as Spell System participant Canvas as Canvas participant EventBus as EventBus participant UI as HUD Display Player->>Rune: click CAST (or press SPACE) Rune->>Rune: validate spell composition Rune->>Currency: currency.canAfford('mana', spellCost) alt Can Afford Currency->>Currency: return true Currency->>EventBus: emit('spell-cast-start', {slots, elements}) EventBus->>Currency: currency.add('mana', -spellCost) EventBus->>UI: floatingText("-{cost}💧", runeCircle, cyan) EventBus->>UI: updateDisplay('mana') EventBus->>Spell: castSpell({elements, target}) Note over Spell: Build spell properties:\n- Damage: base * elements * mastery\n- Type: combination of elements\n- Speed: based on element weights Spell->>Canvas: spawnProjectile({x, y, type, damage, target}) Canvas->>Canvas: animate projectile flight Note over Canvas: Projectile hits target: Canvas->>EventBus: emit('projectile-hit', {target, damage, elements}) EventBus->>Spell: applyDamage({target, damage, elements}) alt Enemy killed Spell->>EventBus: emit('enemy-killed', {...}) EventBus->>Collectible: spawnCollectible(...) end else Cannot Afford Currency->>Currency: return false Currency->>EventBus: emit('spell-cast-failed', 'insufficient-mana') EventBus->>UI: showError("Not enough mana!") EventBus->>Canvas: shake rune circle end ``` ### Passive Mana Regeneration ```mermaid sequenceDiagram participant GameLoop as Game Loop participant Currency as CurrencyManager participant UI as HUD Display participant EventBus as EventBus Note over GameLoop: Every 1 second GameLoop->>Currency: currency.regen('mana') Currency->>Currency: calculate regen amount\nbaseRegen (2) + manaMasteryLevel Currency->>Currency: currentMana < maxMana ? add regen : 0 Currency->>EventBus: emit('mana-regened', {amount, newBalance}) EventBus->>UI: updateDisplay('mana') Note over UI: No floating text for passive regen\n(subtle update only) ``` ### Overdrive Activation ```mermaid sequenceDiagram participant Player as Player Input participant Charge as Charge System participant Currency as CurrencyManager participant Spell as Spell System participant UI as HUD Display participant Canvas as Canvas Player->>Charge: click Overdrive Bar\n(charge >= 50) Charge->>Currency: currency.canAfford('elementalCharge', 50) alt Can Afford Currency->>Currency: add('elementalCharge', -50) Currency->>Charge: emit('overdrive-activated') Charge->>Spell: setNextSpellMultiplier(3.0) Charge->>Canvas: showOverdriveAura() Charge->>UI: flashOverdriveIndicator() Note over Canvas: Next spell cast within 5s\ngets 3x damage + visual aura Canvas->>Canvas: rune circle glows with elemental color UI->>UI: show "OVERDRIVE ACTIVE" text Note over Charge,Spell: Spell cast happens normally\nbut damage *= 3 Spell->>Charge: emit('overdrive-consumed') Charge->>Canvas: hideOverdriveAura() Charge->>UI: hideOverdriveIndicator() else Cannot Afford Charge->>UI: showError("Need 50 Charge!") Charge->>Canvas: shake charge bar end ``` ### Iron to Essence Conversion ```mermaid sequenceDiagram participant Player as Player Input participant UI as Upgrade Panel participant Currency as CurrencyManager participant EventBus as EventBus participant HUD as HUD Display Player->>UI: click "Convert to Essence" button\n(Iron >= 100) UI->>Currency: currency.canAfford('ironShards', 100) alt Can Afford Currency->>Currency: add('ironShards', -100) Currency->>Currency: add('crystalEssence', 1) Currency->>EventBus: emit('conversion-complete', {from: 'ironShards', to: 'crystalEssence', amount: 1}) EventBus->>UI: floatingText("-100⚙️", button, silver) EventBus->>UI: floatingText("+1💎", button, purple) EventBus->>HUD: updateDisplay('ironShards') EventBus->>HUD: updateDisplay('crystalEssence') Note over HUD: Crystal essence increase gets\ncelebration effect (flash + sound) else Cannot Afford UI->>UI: showButtonDisabled("Need 100 Iron Shards") end ``` ## CONFIG Spec: currencies Section ```javascript // Currency System Configuration for Spellforge Arena // This file defines all currencies, sources, sinks, and conversions CONFIG.currencies = { mana: { displayName: 'Mana', icon: '💧', startingAmount: 20, cap: 100, // Base cap, increases with upgrades capPerUpgrade: 20, // +20 per Mana Cap upgrade decimals: 0, suffixes: [], // Mana doesn't use suffixes - capped values persistsOnPrestige: false, regenRate: 2, // Base mana regen per second regenPerMastery: 1, // +1 per Mana Mastery level }, ironShards: { displayName: 'Iron Shards', icon: '⚙️', startingAmount: 0, cap: null, // Uncapped decimals: 0, suffixes: ['K', 'M', 'B'], persistsOnPrestige: false, }, crystalEssence: { displayName: 'Crystal Essence', icon: '💎', startingAmount: 0, cap: null, // Uncapped decimals: 0, suffixes: ['K', 'M'], persistsOnPrestige: true, }, elementalCharge: { displayName: 'Elemental Charge', icon: '⚡', startingAmount: 0, cap: 100, // Hard cap decimals: 0, suffixes: [], persistsOnPrestige: false, decayRate: 1, // -1 per 3 seconds decayInterval: 3000, // Decay every 3 seconds (ms) }, }; CONFIG.currencySources = { // Primary Gameplay Sources wispKillMana: { currency: 'mana', baseReward: 3, formula: 'baseReward', // Flat reward per Wisp kill collectible: 'manaFragment', chance: 1.0, // 100% drop chance }, guardianKillMana: { currency: 'mana', baseReward: 2, formula: 'baseReward', collectible: 'manaFragment', chance: 1.0, }, guardianKillIron: { currency: 'ironShards', baseReward: 5, formula: 'baseReward * (1 + 0.05 * waveNumber)', collectible: 'ironShard', chance: 1.0, }, golemKillIron: { currency: 'ironShards', baseReward: 15, formula: 'baseReward * (1 + 0.05 * waveNumber)', collectible: 'ironShard', chance: 1.0, }, golemKillEssence: { currency: 'crystalEssence', baseReward: 1, formula: 'baseReward', collectible: 'crystalEssence', chance: 0.3, // 30% chance }, championKillIron: { currency: 'ironShards', baseReward: 20, formula: 'baseReward * (1 + 0.05 * waveNumber)', collectible: 'ironShard', chance: 1.0, }, championKillEssence: { currency: 'crystalEssence', baseReward: 3, formula: 'baseReward + Math.floor(waveNumber / 5)', collectible: 'crystalEssence', chance: 0.6, // 60% chance }, // Wave Completion Bonus waveCompleteMana: { currency: 'mana', baseReward: 10, formula: 'baseReward * waveNumber', direct: true, // Added directly, not a collectible }, // Element Sprite Collection elementSpriteCharge: { currency: 'elementalCharge', baseReward: 2, formula: 'baseReward', collectible: 'elementSprite', chance: 1.0, }, elementSpriteMana: { currency: 'mana', baseReward: 1, formula: 'baseReward', collectible: 'elementSprite', chance: 1.0, }, elementSpriteIron: { currency: 'ironShards', baseReward: 1, formula: 'baseReward', collectible: 'elementSprite', chance: 0.2, // 20% chance }, // Same-Element Spell Chain (Charge Building) sameElementSpellChain: { currency: 'elementalCharge', baseReward: 10, formula: 'baseReward * (1 + 0.1 * chainLength)', // More for longer chains direct: true, condition: 'lastSpellElement === currentSpellElement', }, enemyWeaknessKill: { currency: 'elementalCharge', baseReward: 5, formula: 'baseReward', direct: true, condition: 'spellElement === enemy.weakness', }, // Prestige Bonus prestigeEssence: { currency: 'crystalEssence', formula: 'maxWaveReached * 0.5 + eliteChampionsKilled * 2', direct: true, }, }; CONFIG.collectibles = { manaFragment: { sprite: 'spark', color: '#00ffff', // Cyan scale: 1.2, lifetime: 8, // seconds before expiry collectRadius: 20, // pixels bobAmplitude: 2, // pixels bobSpeed: 2, // Hz spawnAnimation: 'popIn', spawnAnimationDuration: 200, // ms collectAnimation: 'burst', particleCount: 5, particleColor: '#00ffff', value: 3, sound: 'mana_collect', magnetRadius: 100, // px - starts attracting when close magnetStrength: 200, // px/sec - move speed toward player showsValue: true, }, ironShard: { sprite: 'spark', color: '#808080', // Gray scale: 1.5, lifetime: 10, collectRadius: 22, bobAmplitude: 2, bobSpeed: 1.5, spawnAnimation: 'popIn', spawnAnimationDuration: 250, collectAnimation: 'burst', particleCount: 7, particleColor: '#a0a0a0', value: 5, // Base value, varies by enemy sound: 'iron_collect', magnetRadius: 120, magnetStrength: 180, showsValue: true, metallic: true, // Special property for visual effect }, ironShardLarge: { extends: 'ironShard', scale: 2.0, value: 15, // Golem/Champion value particleCount: 10, }, crystalEssence: { sprite: 'spark', color: '#9932cc', // Purple scale: 2.0, lifetime: 15, collectRadius: 25, // Generous bobAmplitude: 3, bobSpeed: 1, spawnAnimation: 'popIn', spawnAnimationDuration: 400, collectAnimation: 'burst', particleCount: 15, particleColor: '#b34dff', value: 1, sound: 'essence_collect', magnetRadius: 150, magnetStrength: 250, showsValue: true, glow: true, // Special glow effect neverDespawnOnScreen: true, // Stay until collected if visible celebrate: true, // Triggers celebration effect }, elementSprite: { sprite: 'spark', color: 'varies', // Set by element type scale: 1.0, lifetime: 6, collectRadius: 18, bobAmplitude: 2, bobSpeed: 2.5, spawnAnimation: 'fadeIn', spawnAnimationDuration: 300, collectAnimation: 'burst', particleCount: 3, particleColor: 'varies', value: 2, // Charge value sound: 'element_collect', magnetRadius: 80, magnetStrength: 150, showsValue: true, orbit: true, // Orbits near rune circle orbitRadius: 60, orbitSpeed: 1, }, }; CONFIG.upgradeCosts = { // Rune Slot Unlocks runeSlot4: { baseCost: 100, costMultiplier: 1.0, // Flat cost, not repeatable currency: 'ironShards', requires: 'waveNumber >= 5', }, runeSlot5: { baseCost: 500, costMultiplier: 1.0, currency: 'ironShards', requires: 'waveNumber >= 10 && runeSlot4', }, // Elemental Masteries (one per element) fireMastery: { baseCost: 30, costMultiplier: 1.3, currency: 'ironShards', maxLevel: 10, effect: { type: 'damage', element: 'fire', perLevel: 0.1 }, // +10% fire damage per level }, iceMastery: { baseCost: 30, costMultiplier: 1.3, currency: 'ironShards', maxLevel: 10, effect: { type: 'damage', element: 'ice', perLevel: 0.1 }, }, arcaneMastery: { baseCost: 30, costMultiplier: 1.3, currency: 'ironShards', maxLevel: 10, effect: { type: 'damage', element: 'arcane', perLevel: 0.1 }, }, voidMastery: { baseCost: 30, costMultiplier: 1.3, currency: 'ironShards', maxLevel: 10, effect: { type: 'damage', element: 'void', perLevel: 0.1 }, }, // Spell Damage (all elements) spellDamage: { baseCost: 50, costMultiplier: 1.2, currency: 'ironShards', maxLevel: 15, effect: { type: 'damage', element: 'all', perLevel: 0.05 }, // +5% all damage per level }, // Mana System manaMastery: { baseCost: 30, costMultiplier: 1.3, currency: 'mana', maxLevel: 5, effect: { type: 'regen', perLevel: 1 }, // +1 mana/sec per level }, unlockElement: { baseCost: 25, costMultiplier: 1.0, currency: 'mana', oneTime: true, requires: '!elementUnlocked', }, // Permanent Upgrades (Crystal Essence) permanentRuneSlot: { baseCost: 50, costMultiplier: 1.5, // Each subsequent permanent slot costs more currency: 'crystalEssence', maxPurchases: 2, // Can only buy 2 permanent slots effect: { type: 'permanent', property: 'startingRuneSlots', value: 1 }, persists: true, }, elementalAttunement: { baseCost: 100, costMultiplier: 1.3, currency: 'crystalEssence', maxLevel: 5, effect: { type: 'damage', element: 'chosen', perLevel: 0.1 }, persists: true, }, manaCapUpgrade: { baseCost: 75, costMultiplier: 1.3, currency: 'crystalEssence', maxPurchases: 5, effect: { type: 'cap', currency: 'mana', value: 20 }, persists: true, }, startingManaUpgrade: { baseCost: 60, costMultiplier: 1.4, currency: 'crystalEssence', maxPurchases: 3, effect: { type: 'startingAmount', currency: 'mana', value: 10 }, persists: true, }, }; CONFIG.spellCosts = { // Mana cost to cast spells based on rune slot count base: 3, // Base cost per rune slot perSlot: 1, // Additional cost per slot formula: 'baseCost + (runeSlots - 3) * perSlot', // 3 slots = 3 mana, 4 slots = 4 mana, 5 slots = 5 mana // Element-specific cost modifiers elementCosts: { fire: 1.0, // Normal cost ice: 1.0, arcane: 1.2, // +20% cost (more powerful) void: 1.5, // +50% cost (most powerful) }, }; CONFIG.conversions = { ironToEssence: { input: { currency: 'ironShards', amount: 100 }, output: { currency: 'crystalEssence', amount: 1 }, unlockCondition: 'true', // Always available cooldown: 0, // No cooldown oneWay: true, }, }; CONFIG.balanceTargets = { firstSpellCost: 3, // 15% of starting mana firstUpgradeAffordable: 10, // seconds firstRuneSlotUnlockTime: 240, // seconds (4 minutes) firstEssenceDropTime: 300, // seconds (5 minutes - first Golem) prestigeTime: 1500, // seconds (25 minutes) }; ``` ## Exact Formulas ``` Spell cost: baseCost (3) + (runeSlots - 3) * perSlot (1) Total spell cost: baseCost * elementMultiplier Upgrade cost: baseCost * costMultiplier^level Enemy kill reward: baseReward * (1 + 0.05 * waveNumber) Golem essence chance: 30% fixed Champion essence chance: 60% fixed Wave complete bonus: 10 * waveNumber Mana Mana regen: 2 + manaMasteryLevel (per second) Mana cap: 100 + (manaCapLevel * 20) Elemental charge from spell chain: 10 * (1 + 0.1 * chainLength) Elemental charge from weakness kill: 5 Elemental charge decay: -1 per 3 seconds Conversion: floor(ironShards / 100) → essence Prestige essence bonus: maxWave * 0.5 + eliteKills * 2 Rune slot unlock costs: - Slot 4: 100 Iron (flat) - Slot 5: 500 Iron (flat) Mastery costs: 30 * 1.3^level Spell damage upgrade: 50 * 1.2^level ``` ## Balance Targets | Time | Mana | Iron Shards | Crystal Essence | Key Event | |------|------|-------------|-----------------|-------------| | 0:00 | 20 | 0 | 0 | Game start | | 0:05 | ~12 | 0 | 0 | First spell cast (-3 mana) | | 0:30 | ~25 | 5 | 0 | First Iron Shard (Guardian kill) | | 1:00 | ~35 | 15 | 0 | Wave 1 complete (+10 mana) | | 2:00 | ~50 | 45 | 0 | First mastery affordable (30 Iron) | | 3:00 | ~60 | 80 | 0 | Multiple upgrades purchased | | 4:00 | ~70 | 120 | 0 | Rune slot 4 affordable (100 Iron) | | 5:00 | ~80 | 150 | 0-1 | First Golem (Essence possible) | | 10:00 | ~150 | 400 | 0-2 | Wave 10 - Rune slot 5 visible | | 15:00 | ~200 | 800 | 2-5 | Mid-game plateau | | 20:00 | ~250 | 1500 | 5-10 | First permanent upgrade affordable | | 25:00 | ~300 | 2500 | 10-20 | Prestige recommended | | 30:00 | ~400 | 4000 | 15-30 | Late game, all unlocks | ## Edge Cases - **Overflow protection**: Switch to BigNum at 1e6 for Iron Shards and Crystal Essence - **Negative balance**: `canAfford()` check before all purchases; show error feedback - **Mana cap at zero**: Spells disabled, show "Not enough mana" error, shake rune circle - **Elemental charge decay only when above 0**: Don't show negative values - **Collectible spawning overlaps**: Randomize spawn position slightly to prevent exact overlap - **Collectible lifetime during pause**: Pause lifetime countdown when game is paused - **Conversion when can't afford more essence upgrades**: Still allow - player might want to bank for future - **Prestige with no essence**: Still allow - essence bonus on next run will accumulate - **Iron shard overflow**: Ensure suffixes (K/M/B) display correctly; use BigNum library - **Multiple collectibles on screen**: Performance check - limit to 50 active collectibles max - **Element sprite spawning when none collected**: Continue spawning but limit to 5 active max ## Inflation Control Strategies 1. **Mana**: Hard cap prevents infinite accumulation; spell costs ensure constant drain 2. **Iron Shards**: Exponential upgrade costs (1.2-1.3x) eventually outpace linear income growth; 100:1 conversion drains surplus 3. **Crystal Essence**: Very expensive permanent upgrades (50-100 base with 1.3-1.5x scaling); slow accumulation rate 4. **Elemental Charge**: Hard cap at 100, decay mechanism, resets on prestige - designed to be spent, not hoarded

Progression

{
  "gameName": "Spellforge Arena",
  "progression": {
    "unlocks": {
      "firstSpellCast": {
        "requirement": "spellsCast >= 1",
        "unlocks": "spellSystem",
        "toast": "Spell system active!",
        "indicator": "rune-glow"
      },
      "wave1Complete": {
        "requirement": "wavesCompleted >= 1",
        "unlocks": "waveBonuses",
        "toast": "Wave cleared! +10 Mana",
        "indicator": "hud-flash"
      },
      "ironCollected": {
        "requirement": "ironShards >= 10",
        "unlocks": "upgradesPanel",
        "toast": "Upgrades available!",
        "indicator": "tab-glow"
      },
      "wave3Complete": {
        "requirement": "wavesCompleted >= 3",
        "unlocks": "elementSprites",
        "toast": "Element sprites discovered!",
        "indicator": "canvas-new-entity"
      },
      "wave5Complete": {
        "requirement": "wavesCompleted >= 5",
        "unlocks": "runeSlot4",
        "toast": "4th rune slot unlocked!",
        "indicator": "rune-slot-appear"
      },
      "chargeFilled": {
        "requirement": "elementalCharge >= 50",
        "unlocks": "overdrive",
        "toast": "Overdrive ready!",
        "indicator": "bar-glow"
      },
      "championKilled": {
        "requirement": "championsKilled >= 1",
        "unlocks": "crystalEssence",
        "toast": "Crystal Essence discovered!",
        "indicator": "hud-reveal"
      },
      "wave10Complete": {
        "requirement": "wavesCompleted >= 10",
        "unlocks": "runeSlot5",
        "toast": "5th rune slot unlocked!",
        "indicator": "rune-slot-appear"
      },
      "wave12Complete": {
        "requirement": "wavesCompleted >= 12",
        "unlocks": "prestigeTeaser",
        "toast": "Prestige available...",
        "indicator": "button-pulse"
      }
    },
    "milestones": [
      {
        "id": "firstSpark",
        "trigger": "spellsCast >= 1",
        "reward": {
          "mana": 0
        },
        "toast": "The battle begins!"
      },
      {
        "id": "waveBreaker",
        "trigger": "wavesCompleted >= 1",
        "reward": {
          "mana": 10
        },
        "toast": "First wave cleared!"
      },
      {
        "id": "runeSmith",
        "trigger": "runeSlot4Unlocked",
        "reward": {
          "ironShards": 0
        },
        "toast": "Spell complexity doubled!"
      },
      {
        "id": "overcharged",
        "trigger": "overdriveUsed >= 1",
        "reward": {
          "ironShards": 0
        },
        "toast": "UNLEASHED!"
      },
      {
        "id": "championSlayer",
        "trigger": "championsKilled >= 1",
        "reward": {
          "crystalEssence": 0
        },
        "toast": "Champion defeated!"
      },
      {
        "id": "masterRunecaster",
        "trigger": "runeSlot5Unlocked",
        "reward": {
          "ironShards": 0
        },
        "toast": "All combinations unlocked!"
      },
      {
        "id": "elementalAdept",
        "trigger": "anyMasteryLevel >= 5",
        "reward": {
          "crystalEssence": 1
        },
        "toast": "Mastery deepens!"
      },
      {
        "id": "arenaTranscendence",
        "trigger": "prestigesCompleted >= 1",
        "reward": {
          "crystalEssence": 5
        },
        "toast": "A new era begins!"
      }
    ],
    "earlyGame": {
      "firstSpellCost": 3,
      "firstUpgradeAffordable": 90,
      "manaRegenStart": 2,
      "wispManaDrop": 3,
      "guardianIronDrop": 5,
      "wave1Bonus": 10
    }
  },
  "waves": {
    "baseEnemyCount": 2,
    "enemyCountGrowth": 1.15,
    "spawnInterval": 2000,
    "preWaveCountdown": 3,
    "postWaveBreather": 5,
    "bossWaveInterval": 5,
    "waveTimeout": 90
  },
  "waveComposition": {
    "description": "Wave-specific enemy compositions",
    "getEnemies": "function(waveNum) { const baseCount = Math.floor(2 * Math.pow(1.15, waveNum - 1)); const enemies = []; if (waveNum <= 4) { const wispCount = Math.ceil(baseCount * 0.6); const guardianCount = Math.floor(baseCount * 0.4); for (let i = 0; i < wispCount; i++) { enemies.push({ type: 'wisp', delay: i * 1500 }); } for (let i = 0; i < guardianCount; i++) { enemies.push({ type: 'guardian', delay: (wispCount + i) * 2000 }); } } else if (waveNum <= 9) { const hasGolem = waveNum === 5; const hasChampion = waveNum >= 7; const wispCount = Math.ceil(baseCount * 0.4); const guardianCount = Math.floor(baseCount * 0.5); let delay = 0; if (hasGolem) { enemies.push({ type: 'golem', delay: 30000 }); delay += 2000; } if (hasChampion) { enemies.push({ type: 'champion', delay: 60000 }); delay += 2000; } for (let i = 0; i < wispCount; i++) { enemies.push({ type: 'wisp', delay: delay + i * 1200 }); } for (let i = 0; i < guardianCount; i++) { enemies.push({ type: 'guardian', delay: delay + (wispCount + i) * 1800 }); } } else { const hasGolem = waveNum % 5 === 0; const hasChampion = true; const wispCount = Math.ceil(baseCount * 0.35); const guardianCount = Math.floor(baseCount * 0.45); let delay = 0; if (hasGolem) { enemies.push({ type: 'golem', delay: 25000 }); delay += 2000; } enemies.push({ type: 'champion', delay: 50000 }); delay += 2000; for (let i = 0; i < wispCount; i++) { enemies.push({ type: 'wisp', delay: delay + i * 1000 }); } for (let i = 0; i < guardianCount; i++) { enemies.push({ type: 'guardian', delay: delay + (wispCount + i) * 1500 }); } } return enemies; }",
    "getElementalWeakness": "function(waveNum) { const elements = ['fire', 'ice', 'arcane', 'void']; return elements[waveNum % 4]; }",
    "getReward": "function(waveNum) { return { mana: waveNum * 10 }; }"
  },
  "entityUnlocks": {
    "wisp": {
      "unlockWave": 1,
      "spawnCondition": "always",
      "hp": 10,
      "speed": 2.5,
      "damage": 10,
      "reward": {
        "mana": 3
      }
    },
    "guardian": {
      "unlockWave": 1,
      "spawnCondition": "always",
      "hp": 30,
      "speed": 1,
      "damage": 15,
      "reward": {
        "mana": 2,
        "ironShards": 5
      },
      "weakness": {
        "fire": 0.2
      },
      "resistance": {
        "ice": 0.2
      }
    },
    "golem": {
      "unlockWave": 5,
      "spawnCondition": "waveNum % 5 === 0",
      "hp": 150,
      "speed": 0.3,
      "damage": 25,
      "reward": {
        "mana": 5,
        "ironShards": 15,
        "crystalEssence": 0.3
      },
      "weakness": {
        "void": 1
      },
      "resistance": {
        "fire": 0.5,
        "ice": 0.5
      },
      "isBoss": true,
      "announce": 30000
    },
    "champion": {
      "unlockWave": 7,
      "spawnCondition": "waveNum >= 7",
      "hp": 80,
      "speed": 1.2,
      "damage": 20,
      "reward": {
        "mana": 5,
        "ironShards": 20,
        "crystalEssence": 0.6
      },
      "weakness": "rotating",
      "abilities": [
        "summonMinions",
        "counterspell"
      ],
      "isElite": true,
      "announce": 5000
    }
  },
  "prestige": {
    "teaserWave": 12,
    "minWave": 15,
    "recommendedWave": 18,
    "formula": "floor(maxWaveReached * 0.5 + eliteChampionsKilled * 2 + golemsKilled * 0.5)",
    "resets": {
      "currencies": [
        "mana",
        "ironShards",
        "elementalCharge"
      ],
      "upgrades": [
        "runeSlot4",
        "runeSlot5",
        "elementalMasteries",
        "spellDamage",
        "manaMastery"
      ],
      "wave": 0,
      "arenaTier": 0
    },
    "persists": {
      "currencies": [
        "crystalEssence"
      ],
      "upgrades": [
        "permanentRuneSlot",
        "elementalAttunement",
        "manaCapUpgrade",
        "startingManaUpgrade"
      ],
      "achievements": [
        "totalPrestiges",
        "maxWaveReached",
        "totalKills"
      ]
    },
    "visualTiers": [
      {
        "tier": 0,
        "minPrestiges": 0,
        "background": "#1a1a2e",
        "arenaPattern": "basic-pentagram",
        "enemyPalette": null,
        "runeCircle": "stone"
      },
      {
        "tier": 1,
        "minPrestiges": 1,
        "background": "#2e1a3e",
        "arenaPattern": "intricate-pentagram",
        "enemyPalette": {
          "hueShift": 30,
          "saturate": 1.2
        },
        "runeCircle": "glowing-lines"
      },
      {
        "tier": 2,
        "minPrestiges": 3,
        "background": "#3e1a4e",
        "arenaPattern": "multi-layered",
        "enemyPalette": {
          "hueShift": 60,
          "saturate": 1.4
        },
        "runeCircle": "floating-glyphs"
      },
      {
        "tier": 3,
        "minPrestiges": 5,
        "background": "#4e1a5e",
        "arenaPattern": "sanctum",
        "enemyPalette": {
          "hueShift": 90,
          "saturate": 1.6
        },
        "runeCircle": "energy-vortex"
      }
    ],
    "upgrades": {
      "permanentRuneSlot": {
        "baseCost": 50,
        "costMultiplier": 1.5,
        "maxPurchases": 2,
        "effect": {
          "type": "permanent",
          "property": "startingRuneSlots",
          "value": 1
        },
        "description": "+1 permanent rune slot (persists across prestiges)"
      },
      "elementalAttunement": {
        "baseCost": 100,
        "costMultiplier": 1.3,
        "maxLevel": 5,
        "requiresUserChoice": true,
        "effect": {
          "type": "damage",
          "element": "chosen",
          "perLevel": 0.1
        },
        "description": "+10% damage to chosen element (persists)"
      },
      "manaCapUpgrade": {
        "baseCost": 75,
        "costMultiplier": 1.3,
        "maxPurchases": 5,
        "effect": {
          "type": "cap",
          "currency": "mana",
          "value": 20
        },
        "description": "+20 maximum Mana (persists)"
      },
      "startingManaUpgrade": {
        "baseCost": 60,
        "costMultiplier": 1.4,
        "maxPurchases": 3,
        "effect": {
          "type": "startingAmount",
          "currency": "mana",
          "value": 10
        },
        "description": "+10 starting Mana (persists)"
      },
      "chargeMastery": {
        "baseCost": 80,
        "costMultiplier": 1.3,
        "maxPurchases": 3,
        "effect": {
          "type": "chargeCap",
          "value": 20
        },
        "description": "+20 maximum Elemental Charge (persists)"
      },
      "overdriveEfficiency": {
        "baseCost": 120,
        "costMultiplier": 1.5,
        "maxPurchases": 2,
        "effect": {
          "type": "overdriveCost",
          "value": -5
        },
        "description": "Overdrive costs 5 less Charge (persists)"
      }
    },
    "acceleration": {
      "firstPrestige": {
        "waveSpeed": 1.5,
        "incomeMultiplier": 1.3,
        "unlockCheaper": 0.8
      },
      "secondPrestige": {
        "waveSpeed": 2,
        "incomeMultiplier": 1.5,
        "unlockCheaper": 0.7
      }
    }
  },
  "upgradeTiers": {
    "tier1": {
      "fireMastery": {
        "baseCost": 30,
        "costMultiplier": 1.3,
        "currency": "ironShards",
        "maxLevel": 10,
        "effect": {
          "type": "damage",
          "element": "fire",
          "perLevel": 0.1
        },
        "description": "+10% Fire damage per level",
        "canvasChange": "fire-spell-trail-langer"
      },
      "iceMastery": {
        "baseCost": 30,
        "costMultiplier": 1.3,
        "currency": "ironShards",
        "maxLevel": 10,
        "effect": {
          "type": "damage",
          "element": "ice",
          "perLevel": 0.1
        },
        "description": "+10% Ice damage per level",
        "canvasChange": "ice-spell-freeze-langer"
      },
      "arcaneMastery": {
        "baseCost": 30,
        "costMultiplier": 1.3,
        "currency": "ironShards",
        "maxLevel": 10,
        "effect": {
          "type": "damage",
          "element": "arcane",
          "perLevel": 0.1
        },
        "description": "+10% Arcane damage per level",
        "canvasChange": "arcane-spell-homing-stronger"
      },
      "voidMastery": {
        "baseCost": 30,
        "costMultiplier": 1.3,
        "currency": "ironShards",
        "maxLevel": 10,
        "effect": {
          "type": "damage",
          "element": "void",
          "perLevel": 0.1
        },
        "description": "+10% Void damage per level",
        "canvasChange": "void-spell-penetration"
      },
      "spellDamage": {
        "baseCost": 50,
        "costMultiplier": 1.2,
        "currency": "ironShards",
        "maxLevel": 15,
        "effect": {
          "type": "damage",
          "element": "all",
          "perLevel": 0.05
        },
        "description": "+5% all spell damage per level",
        "canvasChange": "all-spells-larger"
      },
      "manaMastery": {
        "baseCost": 30,
        "costMultiplier": 1.3,
        "currency": "mana",
        "maxLevel": 5,
        "effect": {
          "type": "regen",
          "perLevel": 1
        },
        "description": "+1 mana regen per second",
        "canvasChange": "mana-bar-fills-visual"
      }
    },
    "tier2": {
      "requires": "waveNumber >= 3",
      "choices": [
        {
          "id": "splashDamage",
          "name": "Splash Spells",
          "baseCost": 100,
          "effect": {
            "type": "splash",
            "radius": 50,
            "damagePercent": 0.5
          },
          "description": "Spells deal 50% damage in small area",
          "canvasChange": "spells-have-explosion-radius",
          "conflictsWith": [
            "piercingShots"
          ]
        },
        {
          "id": "piercingShots",
          "name": "Piercing Shots",
          "baseCost": 100,
          "effect": {
            "type": "piercing",
            "maxTargets": 3
          },
          "description": "Spells hit up to 3 enemies in line",
          "canvasChange": "spells-have-trail-piercing",
          "conflictsWith": [
            "splashDamage"
          ]
        },
        {
          "id": "fasterCasting",
          "name": "Rapid Casting",
          "baseCost": 80,
          "effect": {
            "type": "castSpeed",
            "multiplier": 0.8
          },
          "description": "20% faster spell casting",
          "canvasChange": "cast-animation-faster",
          "conflictsWith": [
            "overchargedSpells"
          ]
        },
        {
          "id": "overchargedSpells",
          "name": "Overcharged Spells",
          "baseCost": 80,
          "effect": {
            "type": "damage",
            "all": 0.2
          },
          "description": "+20% spell damage, slower casting",
          "canvasChange": "spells-have-glow-aura",
          "conflictsWith": [
            "fasterCasting"
          ]
        }
      ]
    },
    "tier3": {
      "requires": "waveNumber >= 8",
      "elementalSynergy": {
        "baseCost": 150,
        "costMultiplier": 1.4,
        "currency": "ironShards",
        "maxLevel": 5,
        "requires": "elementalSpecialization",
        "effect": {
          "type": "sameElementBonus",
          "perLevel": 0.15
        },
        "description": "+15% damage when using same element twice",
        "canvasChange": "same-element-spells-glow-brighter"
      },
      "chargeMastery": {
        "baseCost": 120,
        "costMultiplier": 1.3,
        "currency": "ironShards",
        "maxLevel": 3,
        "requires": "overdriveUnlocked",
        "effect": {
          "type": "chargeCapacity",
          "perLevel": 20
        },
        "description": "+20 Charge capacity",
        "canvasChange": "charge-bar-langer"
      }
    }
  },
  "antiFrustration": {
    "stuckDetection": "If no wave cleared in 90 seconds, boost player spell damage by 50% for 30 seconds",
    "catchupMechanism": "Bad upgrade choices recover via passive mana regen - always gaining resources even when stuck",
    "visualProgress": "Progress bars on locked milestones always visible - '90% to next unlock'",
    "noDeadEnds": "Cannot lose all progress - can always collect mana from Wisps (fast, weak enemies)",
    "forgivingEarlyGame": "First 3 waves have reduced enemy HP by 25% to ensure success",
    "resourceMagnetism": "All collectibles magnet to player after 5 seconds - no frustration from missing drops",
    "clearHorizens": "Always show 'Next unlock in X Iron/Mana/Y waves' - never wondering what to do"
  },
  "motivatorSummary": {
    "next30Seconds": "Almost can afford next upgrade, watching spell effects, collecting drops",
    "next2Minutes": "New rune slot or elemental mastery about to unlock",
    "next5to10Minutes": "Boss wave approaching, Overdrive charge building",
    "session": "Prestige for permanent power, new visual arena, specialization build"
  }
}

Progression

# Spellforge Arena - Progression System Design ## Unlock Flow (MOST IMPORTANT) ```mermaid flowchart TD Start["Game Start\n0:00\n3 rune slots visible"] --> FirstEntities["First enemies spawn on Canvas\nWisps + Guardians appear\nCore gameplay visible immediately"] FirstEntities -->|"First spell cast\n(~5 sec)"| SpellDiscovery["🔓 Unlock: Spell System\nRune slots active\nProjectiles visible on Canvas"] FirstEntities -->|"First Wisp killed\n(~15 sec)"| FirstMana["+3 Mana fragment drop\nCollection mechanic revealed"] SpellDiscovery -->|"Wave 1 complete\n(~45 sec)"| Wave1Reward["🔓 Unlock: Wave Bonus\n+10 Mana awarded\nMana collection visible"] Wave1Reward -->|"10 Iron collected\n(~2 min)"| UpgradesRevealed["🔓 Unlock: Upgrades Panel\nIron Shard upgrades visible\nElemental mastery options"] FirstMana -->|"25 Mana accumulated\n(~1 min)"| ManaAffluent["🔓 Unlock: Mana Mastery\nFirst passive upgrade\nRegen increased"] UpgradesRevealed -->|"Wave 3 complete\n(~4 min)"| ElementSprites["🔓 Unlock: Element Sprites\nColored sparks orbit rune circle\n+2 Charge on collect"] ElementSprites -->|"Wave 5 complete\n+100 Iron earned"| RuneSlot4["🔓 Unlock: 4th Rune Slot\nSpell complexity doubles\nNew combo possibilities"] RuneSlot4 -->|"First charge filled\n(~6 min)"| OverdriveUnlocked["🔓 Unlock: Overdrive Bar\n50 Charge threshold\n3x damage ability"] OverdriveUnlocked -->|"Elite Champion killed\n(~8 min)"| CrystalDrops["🔓 Unlock: Crystal Essence\nPurple drops visible\nPermanent upgrades teased"] CrystalDrops -->|"Wave 10 complete\n(~12 min)"| RuneSlot5["🔓 Unlock: 5th Rune Slot\nMaximum spell complexity\nAll element combos available"] RuneSlot5 -->|"Wave 12 complete\n(~15 min)"| PrestigeTeased["✨ Prestige Button Appears\n'Prestige Available' toast\nShows potential reward"] PrestigeTeased -->|"Wave 15 complete\n(~20 min)"| PrestigeReady["✨ Prestige Recommended\nAll upgrades purchased\nEnemies outscaling defenses"] RuneSlot5 -.->|"Parallel path"| MasteryDeepen["Elemental mastery levels 5+\nSpecialization becomes viable"] MasteryDeepen -->|"50 Crystal Essence\n(~25 min)"| PermanentUpgrade["First permanent upgrade\nPersists across prestiges"] style Start fill:#90EE90 style RuneSlot4 fill:#90D0FF style RuneSlot5 fill:#90D0FF style OverdriveUnlocked fill:#FFD700 style CrystalDrops fill:#9932CC style PrestigeReady fill:#FF6B6B ``` ## Gate Dependency Graph ```mermaid graph TD subgraph "Hard Gates (progress pauses)" HG1["⛔ Gate: First Spell Cast\nRequirement: Cast any spell\nWait: ~5 sec\nBlocks: Mana spending, resource drops"] HG2["⛔ Gate: Wave 1 Complete\nRequirement: Defeat all wave 1 enemies\nWait: ~45 sec\nBlocks: Wave bonuses, progression"] HG3["⛔ Gate: 100 Iron Shards\nRequirement: Collect 100 Iron\nWait: ~4 min\nBlocks: Rune slot 4, mastery tier 2"] HG4["⛔ Gate: Wave 10\nRequirement: Survive to wave 10\nWait: ~12 min\nBlocks: Rune slot 5, late-game content"] HG5["⛔ Gate: Prestige Threshold\nRequirement: Wave 15 complete\nWait: ~20 min\nBlocks: Prestige action, permanent upgrades"] end subgraph "Soft Gates (progress slows)" SG1["🟡 Gate: Early Game Plateau\nWaves 2-4\nIron shard income slows\nPlayer redirected to: Efficiency optimization"] SG2["🟡 Gate: Mid-Game Wall\nWaves 7-9\nEnemy HP outpaces damage\nPlayer redirected to: Mastery upgrades"] SG3["🟡 Gate: Pre-Prestige Grind\nWaves 12-14\nAll upgrades expensive\nPlayer redirected to: Prestige decision"] end subgraph "Choice Gates (strategic branching)" CG1["🔵 Gate: Elemental Specialization\nRequirement: 30 Iron for first mastery\nForces: Fire/Ice/Arcane/Void focus\nChanges: Visual theme, spell effectiveness"] CG2["🔵 Gate: Rune Configuration\nRequirement: 4th slot unlocked\nChoice: More slots vs. More power\nChanges: Combat rhythm, combo depth"] end HG1 --> SG1 SG1 --> HG2 HG2 --> CG1 CG1 --> SG2 SG2 --> HG3 HG3 --> CG2 CG2 --> SG3 SG3 --> HG4 HG4 --> SG3 SG3 --> HG5 ``` ## Progression Timeline ```mermaid gantt title Progression Pacing (30 Minutes to First Prestige) dateFormat mm:ss axisFormat %M:%S section Onboarding (0-2 min) First entities visible on Canvas :active, 00:00, 5s First spell cast & projectile :active, 00:05, 10s First resource drops (Mana/Iron) :active, 00:15, 30s Wave 1 complete - first bonus :active, 00:45, 15s First upgrade affordable :active, 01:30, 30s section Foundation (2-5 min) Upgrades panel revealed :active, 02:00, 60s Element sprites discovered :active, 03:00, 60s First elemental mastery purchased :active, 03:30, 30s Mana mastery unlocks regen :active, 04:00, 60s section Expansion (5-12 min) 4th rune slot unlock :active, 05:00, 90s Overdrive system discovered :active, 06:30, 60s First Elite Champion appears :active, 08:00, 120s Crystal Essence drops visible :active, 09:00, 60s 5th rune slot unlock :active, 12:00, 120s section Mastery (12-20 min) All spell combinations available :active, 15:00, 180s Elemental specialization viable :active, 17:00, 180s First permanent upgrade affordable :active, 20:00, 120s section Climax (20-30 min) Prestige teased & recommended :active, 22:00, 300s All mastery tiers purchased :active, 25:00, 300s Optimal prestige point :milestone, 28:00, 0 ``` ## Tension Curve ```mermaid graph LR subgraph "Emotional Arc" T1["0-2 min\n🟢 Excitement\nTension: 2/5\nFirst spell casts, discovering runes"] T2["2-5 min\n🟢 Discovery\nTension: 3/5\nNew drops, upgrades revealed"] T3["5-7 min\n🟡 First Plateau\nTension: 2/5\nSaving for 4th rune slot"] T4["7-10 min\n🟢 Expansion\nTension: 4/5\nOverdrive, Champions, Essence"] T5["10-15 min\n🟡 Optimization\nTension: 3/5\nMastering spell combinations"] T6["15-20 min\n🟢 Peak\nTension: 5/5\n5th slot, specialization"] T7["20-25 min\n🟡 Push\nTension: 4/5\nGrinding for prestige"] T8["25-30 min\n🟢 Climax\nTension: 5/5\nPrestige decision!"] end T1 --> T2 --> T3 --> T4 --> T5 --> T6 --> T7 --> T8 ``` ## Milestone Rewards ```mermaid graph LR subgraph "Gameplay Milestones" M1["🏆 First Spark\nCast first spell\nReward: Visual discovery\nToast: The battle begins!"] M2["🏆 Wave Breaker\nComplete Wave 1\nReward: +10 Mana\nToast: First wave cleared!"] M3["🏆 Rune Smith\nUnlock 4th rune slot\nReward: Combo discovery\nToast: Spell complexity doubled!"] M4["🏆 Overcharged\nFirst Overdrive use\nReward: 3x damage preview\nToast: UNLEASHED!"] M5["🏆 Champion Slayer\nDefeat Elite Champion\nReward: First Crystal Essence\nToast: Rare essence discovered!"] M6["🏆 Master Runecaster\nUnlock 5th rune slot\nReward: Maximum complexity\nToast: All combinations unlocked!"] M7["🏆 Elemental Adept\nReach mastery level 5\nReward: +50% element damage\nToast: Mastery deepens!"] M8["🏆 Arena Transcendence\nFirst prestige\nReward: Permanent power\nToast: A new era begins!"] end ``` ## Tutorial / First-Time Flow ```mermaid sequenceDiagram actor Player participant Canvas as Game Canvas participant UI as Game UI participant Rune as Rune System Note over Player,UI: First 60 Seconds Player->>Canvas: loads game Canvas->>Player: enemies spawn automatically (Wisps/Guardians) UI->>Player: HUD shows Mana (20/100), Iron (0), Charge (0/100) UI->>Player: 3 rune slots visible at bottom Canvas->>Canvas: enemies move toward rune circle Player->>Rune: clicks first slot (cycles to Fire 🔥) Rune->>Canvas: slot glows orange Player->>Rune: clicks second slot (cycles to Ice ❄️) Rune->>Canvas: slot glows blue Player->>UI: presses SPACE to cast spell Canvas->>Canvas: projectile spawns from rune circle Canvas->>Canvas: projectile travels to target enemy Canvas->>Canvas: HIT - enemy dies with particle effect Canvas->>Player: Mana fragment appears (+3 💧) Player->>Canvas: clicks Mana fragment Canvas->>UI: floating "+3 💧" text UI->>Player: Mana counter animates (20 → 17 → 20 via regen) Player->>Canvas: continues casting, killing enemies Canvas->>UI: Iron Shard drops appear Player->>Canvas: clicks Iron Shard UI->>Player: Iron counter: 0 → 5 ⚙️ Note over Player,UI: At 10 Iron (~90 seconds): UI->>Player: 🔓 Upgrades button glows in bottom panel UI->>Player: tooltip shows "Fire Mastery: 30 Iron" Player->>UI: clicks Fire Mastery upgrade UI->>Canvas: rune circle gets orange glow UI->>Player: toast "Fire Mastery +1! 🔥" Note over Player,Canvas: Player now deals +10% Fire damage\nvisible as larger fire effects on spells ``` ## Entity Spawn/Unlock State Machines ### Player Spell Projectiles ```mermaid stateDiagram-v2 [*] --> Locked: game start Locked --> Unlocked: first spell cast\n(~5 seconds) Unlocked --> Available: player has mana >= spell cost Available --> Spawning: player presses SPACE/clicks CAST Spawning --> Active: spawn animation (100ms)\nscale 0→1 Active --> Traveling: launch from rune circle Traveling --> Impact: collision with enemy Traveling --> Expired: off-screen (2s timeout) Impact --> [*]: deal damage, spawn particles\ncheck enemy death Expired --> [*]: fade out, cleanup note right of Unlocked Toast: "Spell System Active!" Rune slots become interactive Element cycling enabled end note note right of Active Color: based on elemental composition Size: base scale * mastery Trail: particle effect by element Target: homing if Arcane, straight otherwise end note note right of Impact Triggers: enemy.takeDamage(damage) Triggers: projectile.hit visual If enemy dies: spawn collectibles Element-specific effects: Ice (slow), Fire (burn) end note ``` ### Enemy: Wisp ```mermaid stateDiagram-v2 [*] --> Locked: game start Locked --> Unlocked: wave 1 begins\n(always available from start) Unlocked --> Spawning: wave spawn timer Spawning --> Active: spawn at top edge\nfade in (200ms) Active --> Moving: zigzag pathfinding\ntoward rune circle Moving --> Dying: hp <= 0 from spell Moving --> Despawning: reaches rune circle\ndeals damage to player Dying --> Dead: death animation (300ms) Dead --> [*]: spawn Mana fragment\nremove entity note right of Active Sprite: ghost (cyan/white) HP: 10 (low) Speed: Fast (2.5x base) Movement: Erratic zigzag Reward: +3 Mana on kill end note note right of Dying Triggers: death particle burst Triggers: spawnCollectible('manaFragment', position) Triggers: currencyCheck('mana') Sound: ethereal wisp end note ``` ### Enemy: Guardian ```mermaid stateDiagram-v2 [*] --> Locked: game start Locked --> Unlocked: wave 1 begins\n(always available from start) Unlocked --> Spawning: wave spawn timer Spawning --> Active: spawn at top edge\nscale in (250ms) Active --> Moving: straight path\ntoward rune circle Moving --> Fighting: in spell range\n(no attack - just tank) Fighting --> Moving: spell impact resolved Moving --> Dying: hp <= 0 from spell Moving --> Despawning: reaches rune circle\ndeals damage to player Dying --> Dead: death animation (400ms)\nwith metallic flash Dead --> [*]: spawn Iron Shard + Mana\nremove entity note right of Active Sprite: knight (steel gray armor) HP: 30 (moderate) Speed: Medium (1.0x base) Reward: +5 Iron, +2 Mana on kill Weak to: Fire (+20% damage) Strong to: Ice (-20% damage, slowed) end note note right of Dying Triggers: metallic death burst Triggers: spawnCollectible('ironShard', position, 5) Triggers: spawnCollectible('manaFragment', position, 2) Triggers: checkChargeReward() Sound: armor clatter end note ``` ### Enemy: Golem (Boss) ```mermaid stateDiagram-v2 [*] --> Locked: game start Locked --> Teased: wave 4 announced\n"Golem incoming in 3..." Teased --> Unlocked: wave 5 begins Unlocked --> Spawning: boss spawn trigger\n(30s after wave start) Spawning --> Active: dramatic spawn\n(500ms) + screen flash Active --> Moving: slow march\ntoward rune circle Moving --> Dying: hp <= 0 from spell Moving --> Despawning: reaches rune circle\nmassive damage (20) Dying --> Dead: boss death (800ms)\nwith shockwave Dead --> [*]: spawn Iron Shards (x3)\n+ Essence (30% chance)\nmilestone check note right of Teased UI: "⚠️ BOSS INCOMING" Canvas: warning pulse Player: 30s to prepare end note note right of Active Sprite: slime (brown/gray, scale 2.0x) HP: 150 (massive - 5x Guardian) Speed: Very slow (0.3x base) Reward: +15 Iron, 30% chance +1 Essence Weak to: Void (full damage) Strong to: Fire/Ice (50% damage) end note note right of Dying Triggers: screen shake Triggers: particle explosion (20 particles) Triggers: spawnCollectible('ironShardLarge', position, 15) Triggers: if(random < 0.3) spawnCollectible('crystalEssence', position, 1) Triggers: waveComplete() Sound: rumble + crash end note ``` ### Enemy: Elite Champion ```mermaid stateDiagram-v2 [*] --> Locked: game start Locked --> Teased: wave 6 announced\n"Champion approaching..." Teased --> Unlocked: wave 7 begins (3 min after start) Unlocked --> Spawning: champion spawn trigger\n(60s after wave start) Spawning --> Active: teleport in\n(400ms) + purple flash Active --> Moving: purposeful walk\ntoward rune circle Active --> Casting: special ability\n(summon minions or counter-spell) Casting --> Moving: ability complete Moving --> Dying: hp <= 0 from spell Dying --> Dead: champion death (600ms)\nwith energy release Dead --> [*]: spawn Iron Shards (x4)\n+ Essence (60% chance)\nwave advancement note right of Active Sprite: wizard (red/purple, scale 1.2x) HP: 80 (high - 2.5x Guardian) Speed: Medium-fast (1.2x base) Special: Summons 2 Wisps on spawn Reward: +20 Iron, 60% chance +3 Essence Weak to: Rotates each wave (shown on Canvas) end note note right of Casting Every 5 seconds: cast ability Ability 1: Summon 2 Wisps at top Ability 2: Fire counter-spell toward player\n(visible warning for 1s) end note ``` ### Collectible: Element Sprite ```mermaid stateDiagram-v2 [*] --> Locked: game start Locked --> Unlocked: wave 3 complete\n(~4 minutes) Unlocked --> Spawning: periodic timer\nevery 8-12 seconds Spawning --> Active: fade in (300ms)\nat random orbit position Active --> Orbiting: drifts around rune circle\n60px radius Active --> Collected: player clicks within 18px Active --> Expired: lifetime 6s exceeded Collected --> [*]: add Charge + Mana\nparticle burst Expired --> [*]: fade out (200ms) note right of Unlocked Toast: "Element Sprites Appeared!" First spawn: 5s after unlock Color: matches last-cast element end note note right of Orbiting Sprite: spark (element color) Value: +2 Charge, +1 Mana, 20% +1 Iron Bob animation: 2px amplitude, 2.5Hz Collect radius: 18px Magnetism: 80px range at 150px/sec end note ``` ## Wave/Round State Machine ```mermaid stateDiagram-v2 [*] --> PreWave: game start\nprevious wave complete PreWave --> Spawning: countdown complete (3s)\n"Wave N incoming!" Spawning --> Active: all enemies spawned\nplayer can cast spells Active --> BossPhase: boss wave trigger\n(wave 5, 10, 15...) Active --> WaveComplete: all enemies defeated\nor wave timer exceeded (90s) BossPhase --> Active: boss defeated\nminions continue BossPhase --> Failed: player died\nprestige option shown WaveComplete --> Reward: +10 * waveNumber Mana\ncheck milestones Reward --> PreWave: next wave countdown\n(5s breather) Reward --> PrestigeCheck: wave >= 15 PrestigeCheck --> PreWave: prestige declined\ncontinue playing PrestigeCheck --> [*]: prestige accepted\nrun complete note right of PreWave UI: "Wave {n} incoming!" (3s countdown) Canvas: spawn indicators pulse at top Player: last chance to spend, organize end note note right of Spawning Wave 1-4: 2-4 enemies (Wisps + Guardians) Wave 5-9: 4-6 enemies + 1 Golem at wave 5 Wave 10-14: 6-8 enemies + 1 Champion each wave Wave 15+: 8-10 enemies + Golem + Champion end note note right of Active Player casts spells at enemies Enemies drop Mana/Iron on death Element sprites orbit (unlocked at wave 3) Boss health bar visible (if boss wave) Charge meter visible (unlocked at wave 4) end note note right of WaveComplete UI: toast "Wave {n} Complete!" + bonus Canvas: brief flash (white) Iron Shard collectibles magnet to player Check: unlock conditions (rune slots, upgrades) Check: milestone triggers end note ``` ## CONFIG Spec: progression and waves Sections ```javascript // Progression System Configuration for Spellforge Arena CONFIG.progression = { // Unlock thresholds - all trigger on gameplay events unlocks: { firstSpellCast: { requirement: 'spellsCast >= 1', unlocks: 'spellSystem', toast: 'Spell system active!', indicator: 'rune-glow', }, wave1Complete: { requirement: 'wavesCompleted >= 1', unlocks: 'waveBonuses', toast: 'Wave cleared! +10 Mana', indicator: 'hud-flash', }, ironCollected: { requirement: 'ironShards >= 10', unlocks: 'upgradesPanel', toast: 'Upgrades available!', indicator: 'tab-glow', }, wave3Complete: { requirement: 'wavesCompleted >= 3', unlocks: 'elementSprites', toast: 'Element sprites discovered!', indicator: 'canvas-new-entity', }, wave5Complete: { requirement: 'wavesCompleted >= 5', unlocks: 'runeSlot4', toast: '4th rune slot unlocked!', indicator: 'rune-slot-appear', }, chargeFilled: { requirement: 'elementalCharge >= 50', unlocks: 'overdrive', toast: 'Overdrive ready!', indicator: 'bar-glow', }, championKilled: { requirement: 'championsKilled >= 1', unlocks: 'crystalEssence', toast: 'Crystal Essence discovered!', indicator: 'hud-reveal', }, wave10Complete: { requirement: 'wavesCompleted >= 10', unlocks: 'runeSlot5', toast: '5th rune slot unlocked!', indicator: 'rune-slot-appear', }, wave12Complete: { requirement: 'wavesCompleted >= 12', unlocks: 'prestigeTeaser', toast: 'Prestige available...', indicator: 'button-pulse', }, }, // Milestones with rewards milestones: [ { id: 'firstSpark', trigger: 'spellsCast >= 1', reward: { mana: 0 }, toast: 'The battle begins!', }, { id: 'waveBreaker', trigger: 'wavesCompleted >= 1', reward: { mana: 10 }, toast: 'First wave cleared!', }, { id: 'runeSmith', trigger: 'runeSlot4Unlocked', reward: { ironShards: 0 }, toast: 'Spell complexity doubled!', }, { id: 'overcharged', trigger: 'overdriveUsed >= 1', reward: { ironShards: 0 }, toast: 'UNLEASHED!', }, { id: 'championSlayer', trigger: 'championsKilled >= 1', reward: { crystalEssence: 0 }, toast: 'Champion defeated!', }, { id: 'masterRunecaster', trigger: 'runeSlot5Unlocked', reward: { ironShards: 0 }, toast: 'All combinations unlocked!', }, { id: 'elementalAdept', trigger: 'anyMasteryLevel >= 5', reward: { crystalEssence: 1 }, toast: 'Mastery deepens!', }, { id: 'arenaTranscendence', trigger: 'prestigesCompleted >= 1', reward: { crystalEssence: 5 }, toast: 'A new era begins!', }, ], // Early game generosity curve earlyGame: { firstSpellCost: 3, // 15% of starting mana firstUpgradeAffordable: 90, // seconds - 1.5 min to 10 Iron manaRegenStart: 2, // per second - keeps player in game wispManaDrop: 3, // Guaranteed mana from kills guardianIronDrop: 5, // Guaranteed iron from kills wave1Bonus: 10, // Immediate reward }, }; CONFIG.waves = { baseEnemyCount: 2, enemyCountGrowth: 1.15, // enemies per wave = floor(base * growth^(wave-1)) spawnInterval: 2000, // ms between enemy spawns preWaveCountdown: 3, // seconds before wave starts postWaveBreather: 5, // seconds between waves bossWaveInterval: 5, // boss every N waves (5, 10, 15, 20...) waveTimeout: 90, // seconds before wave auto-completes (stuck prevention) }; CONFIG.waveComposition = { // Wave-specific enemy compositions // Returns: [{ type, count, delay }] getEnemies: function(waveNum) { const baseCount = Math.floor(2 * Math.pow(1.15, waveNum - 1)); const enemies = []; // Waves 1-4: Wisps + Guardians only if (waveNum <= 4) { const wispCount = Math.ceil(baseCount * 0.6); const guardianCount = Math.floor(baseCount * 0.4); for (let i = 0; i < wispCount; i++) { enemies.push({ type: 'wisp', delay: i * 1500 }); } for (let i = 0; i < guardianCount; i++) { enemies.push({ type: 'guardian', delay: (wispCount + i) * 2000 }); } } // Waves 5-9: Add Golem at wave 5, then Wisps + Guardians + Champions else if (waveNum <= 9) { const hasGolem = waveNum === 5; const hasChampion = waveNum >= 7; const wispCount = Math.ceil(baseCount * 0.4); const guardianCount = Math.floor(baseCount * 0.5); let delay = 0; if (hasGolem) { enemies.push({ type: 'golem', delay: 30000 }); // Boss at 30s delay += 2000; } if (hasChampion) { enemies.push({ type: 'champion', delay: 60000 }); // Champion at 60s delay += 2000; } for (let i = 0; i < wispCount; i++) { enemies.push({ type: 'wisp', delay: delay + i * 1200 }); } for (let i = 0; i < guardianCount; i++) { enemies.push({ type: 'guardian', delay: delay + (wispCount + i) * 1800 }); } } // Waves 10+: All enemy types else { const hasGolem = waveNum % 5 === 0; const hasChampion = true; const wispCount = Math.ceil(baseCount * 0.35); const guardianCount = Math.floor(baseCount * 0.45); let delay = 0; if (hasGolem) { enemies.push({ type: 'golem', delay: 25000 }); delay += 2000; } enemies.push({ type: 'champion', delay: 50000 }); delay += 2000; for (let i = 0; i < wispCount; i++) { enemies.push({ type: 'wisp', delay: delay + i * 1000 }); } for (let i = 0; i < guardianCount; i++) { enemies.push({ type: 'guardian', delay: delay + (wispCount + i) * 1500 }); } } return enemies; }, // Elemental weakness rotation (for Champions) getElementalWeakness: function(waveNum) { const elements = ['fire', 'ice', 'arcane', 'void']; return elements[waveNum % 4]; // Rotates: fire, ice, arcane, void, fire... }, // Wave rewards getReward: function(waveNum) { return { mana: waveNum * 10, // 10, 20, 30, 40... }; }, }; CONFIG.entityUnlocks = { // When each enemy type becomes available wisp: { unlockWave: 1, spawnCondition: 'always', hp: 10, speed: 2.5, damage: 10, reward: { mana: 3 }, }, guardian: { unlockWave: 1, spawnCondition: 'always', hp: 30, speed: 1.0, damage: 15, reward: { mana: 2, ironShards: 5 }, weakness: { fire: 0.2 }, // +20% from fire resistance: { ice: 0.2 }, // -20% from ice }, golem: { unlockWave: 5, spawnCondition: 'waveNum % 5 === 0', // Every 5th wave hp: 150, speed: 0.3, damage: 25, reward: { mana: 5, ironShards: 15, crystalEssence: 0.3 }, weakness: { void: 1.0 }, // Void does full damage resistance: { fire: 0.5, ice: 0.5 }, // 50% reduction isBoss: true, announce: 30000, // Announce 30s before spawn }, champion: { unlockWave: 7, spawnCondition: 'waveNum >= 7', // Every wave from 7+ hp: 80, speed: 1.2, damage: 20, reward: { mana: 5, ironShards: 20, crystalEssence: 0.6 }, weakness: 'rotating', // Changes each wave abilities: ['summonMinions', 'counterspell'], isElite: true, announce: 5000, // Announce 5s before spawn }, }; CONFIG.prestige = { teaserWave: 12, // Prestige button appears grayed out minWave: 15, // Prestige becomes clickable recommendedWave: 18, // "Recommended" indicator formula: 'floor(maxWaveReached * 0.5 + eliteChampionsKilled * 2 + golemsKilled * 0.5)', resets: { currencies: ['mana', 'ironShards', 'elementalCharge'], upgrades: ['runeSlot4', 'runeSlot5', 'elementalMasteries', 'spellDamage', 'manaMastery'], wave: 0, arenaTier: 0, }, persists: { currencies: ['crystalEssence'], upgrades: ['permanentRuneSlot', 'elementalAttunement', 'manaCapUpgrade', 'startingManaUpgrade'], achievements: ['totalPrestiges', 'maxWaveReached', 'totalKills'], }, visualTiers: [ { tier: 0, minPrestiges: 0, background: '#1a1a2e', arenaPattern: 'basic-pentagram', enemyPalette: null, runeCircle: 'stone', }, { tier: 1, minPrestiges: 1, background: '#2e1a3e', arenaPattern: 'intricate-pentagram', enemyPalette: { hueShift: 30, saturate: 1.2 }, runeCircle: 'glowing-lines', }, { tier: 2, minPrestiges: 3, background: '#3e1a4e', arenaPattern: 'multi-layered', enemyPalette: { hueShift: 60, saturate: 1.4 }, runeCircle: 'floating-glyphs', }, { tier: 3, minPrestiges: 5, background: '#4e1a5e', arenaPattern: 'sanctum', enemyPalette: { hueShift: 90, saturate: 1.6 }, runeCircle: 'energy-vortex', }, ], upgrades: { // Permanent upgrades purchased with Crystal Essence permanentRuneSlot: { baseCost: 50, costMultiplier: 1.5, // Each subsequent slot costs more maxPurchases: 2, effect: { type: 'permanent', property: 'startingRuneSlots', value: 1 }, description: '+1 permanent rune slot (persists across prestiges)', }, elementalAttunement: { baseCost: 100, costMultiplier: 1.3, maxLevel: 5, requiresUserChoice: true, // Player chooses element effect: { type: 'damage', element: 'chosen', perLevel: 0.1 }, description: '+10% damage to chosen element (persists)', }, manaCapUpgrade: { baseCost: 75, costMultiplier: 1.3, maxPurchases: 5, effect: { type: 'cap', currency: 'mana', value: 20 }, description: '+20 maximum Mana (persists)', }, startingManaUpgrade: { baseCost: 60, costMultiplier: 1.4, maxPurchases: 3, effect: { type: 'startingAmount', currency: 'mana', value: 10 }, description: '+10 starting Mana (persists)', }, chargeMastery: { baseCost: 80, costMultiplier: 1.3, maxPurchases: 3, effect: { type: 'chargeCap', value: 20 }, description: '+20 maximum Elemental Charge (persists)', }, overdriveEfficiency: { baseCost: 120, costMultiplier: 1.5, maxPurchases: 2, effect: { type: 'overdriveCost', value: -5 }, description: 'Overdrive costs 5 less Charge (persists)', }, }, // Run 2 acceleration - how much faster is the second run? acceleration: { firstPrestige: { waveSpeed: 1.5, // Reach wave 10 in 2/3 the time incomeMultiplier: 1.3, // 30% more resources unlockCheaper: 0.8, // 20% cheaper to unlock things }, secondPrestige: { waveSpeed: 2.0, // 2x faster incomeMultiplier: 1.5, unlockCheaper: 0.7, }, }, }; CONFIG.upgradeTiers = { // Tier 1: Available from game start - Direct stat boosts tier1: { fireMastery: { baseCost: 30, costMultiplier: 1.3, currency: 'ironShards', maxLevel: 10, effect: { type: 'damage', element: 'fire', perLevel: 0.1 }, description: '+10% Fire damage per level', canvasChange: 'fire-spell-trail-longer', }, iceMastery: { baseCost: 30, costMultiplier: 1.3, currency: 'ironShards', maxLevel: 10, effect: { type: 'damage', element: 'ice', perLevel: 0.1 }, description: '+10% Ice damage per level', canvasChange: 'ice-spell-freeze-longer', }, arcaneMastery: { baseCost: 30, costMultiplier: 1.3, currency: 'ironShards', maxLevel: 10, effect: { type: 'damage', element: 'arcane', perLevel: 0.1 }, description: '+10% Arcane damage per level', canvasChange: 'arcane-spell-homing-stronger', }, voidMastery: { baseCost: 30, costMultiplier: 1.3, currency: 'ironShards', maxLevel: 10, effect: { type: 'damage', element: 'void', perLevel: 0.1 }, description: '+10% Void damage per level', canvasChange: 'void-spell-penetration', }, spellDamage: { baseCost: 50, costMultiplier: 1.2, currency: 'ironShards', maxLevel: 15, effect: { type: 'damage', element: 'all', perLevel: 0.05 }, description: '+5% all spell damage per level', canvasChange: 'all-spells-larger', }, manaMastery: { baseCost: 30, costMultiplier: 1.3, currency: 'mana', maxLevel: 5, effect: { type: 'regen', perLevel: 1 }, description: '+1 mana regen per second', canvasChange: 'mana-bar-fills-visual', }, }, // Tier 2: Unlock at wave 3+ - Build diversity (mutually exclusive paths) tier2: { requires: 'waveNumber >= 3', choices: [ { id: 'splashDamage', name: 'Splash Spells', baseCost: 100, effect: { type: 'splash', radius: 50, damagePercent: 0.5 }, description: 'Spells deal 50% damage in small area', canvasChange: 'spells-have-explosion-radius', conflictsWith: ['piercingShots'], }, { id: 'piercingShots', name: 'Piercing Shots', baseCost: 100, effect: { type: 'piercing', maxTargets: 3 }, description: 'Spells hit up to 3 enemies in line', canvasChange: 'spells-have-trail-piercing', conflictsWith: ['splashDamage'], }, { id: 'fasterCasting', name: 'Rapid Casting', baseCost: 80, effect: { type: 'castSpeed', multiplier: 0.8 }, description: '20% faster spell casting', canvasChange: 'cast-animation-faster', conflictsWith: ['overchargedSpells'], }, { id: 'overchargedSpells', name: 'Overcharged Spells', baseCost: 80, effect: { type: 'damage', all: 0.2 }, description: '+20% spell damage, slower casting', canvasChange: 'spells-have-glow-aura', conflictsWith: ['fasterCasting'], }, ], }, // Tier 3: Unlock at wave 8+ - Synergy bonuses tier3: { requires: 'waveNumber >= 8', elementalSynergy: { baseCost: 150, costMultiplier: 1.4, currency: 'ironShards', maxLevel: 5, requires: 'elementalSpecialization', effect: { type: 'sameElementBonus', perLevel: 0.15 }, description: '+15% damage when using same element twice', canvasChange: 'same-element-spells-glow-brighter', }, chargeMastery: { baseCost: 120, costMultiplier: 1.3, currency: 'ironShards', maxLevel: 3, requires: 'overdriveUnlocked', effect: { type: 'chargeCapacity', perLevel: 20 }, description: '+20 Charge capacity', canvasChange: 'charge-bar-longer', }, }, }; ``` ## Anti-Frustration Features - **Stuck Detection**: If no wave cleared in 90 seconds, boost player spell damage by 50% for 30 seconds - **Catchup Mechanism**: Bad upgrade choices recover via passive mana regen - always gaining resources even when stuck - **Visual Progress**: Progress bars on locked milestones always visible - "90% to next unlock" - **No Dead Ends**: Cannot lose all progress - can always collect mana from Wisps (fast, weak enemies) - **Forgiving Early Game**: First 3 waves have reduced enemy HP by 25% to ensure success - **Resource Magnetism**: All collectibles magnet to player after 5 seconds - no frustration from missing drops - **Clear Horizons**: Always show "Next unlock in X Iron/Mana/Y waves" - never wondering what to do ## Motivator Summary | Timeframe | What Drives Player | |-----------|----------------------| | Next 30 sec | Almost can afford next upgrade, watching spell effects, collecting drops | | Next 2 min | New rune slot or elemental mastery about to unlock | | Next 5-10 min | Boss wave approaching, Overdrive charge building | | Session | Prestige for permanent power, new visual arena, specialization build |

Ui Ux

{
  "gameName": "Spellforge Arena",
  "ui-ux": {
    "overview": "Dark mystical arena theme with deep purple/blue background and elemental accents (cyan, orange, violet). Canvas game world dominates 70% of screen showing rune circle at bottom, enemies descending from above, and spell projectiles flying across screen. UI is minimal and secondary - dark bottom panel for upgrades and top HUD bar for currencies.",
    "colorPalette": {
      "background": {
        "primary": "#1a1a2e",
        "secondary": "#141630",
        "tertiary": "#2a2a4e",
        "canvas": "#1a1a2e"
      },
      "text": {
        "primary": "#e0e0e0",
        "secondary": "#a0a0a0",
        "muted": "#606060"
      },
      "accents": {
        "mana": "#00ffff",
        "iron": "#c0c0c0",
        "charge": "#ffcc00",
        "success": "#4caf50",
        "warning": "#ff9800",
        "danger": "#f44336",
        "prestige": "#9932cc",
        "spellFire": "#ff6b354",
        "spellIce": "#00ffff",
        "spellArcane": "#bf5eff",
        "spellVoid": "#1a1a2e"
      }
    },
    "typography": {
      "fontFamily": "'Cinzel', 'Segoe UI', Tahoma, sans-serif",
      "headings": {
        "weight": "600-700",
        "sizes": {
          "title": "24px",
          "section": "18px",
          "card": "14px"
        }
      },
      "bodyText": {
        "weight": "400",
        "size": "13px"
      },
      "numbers": {
        "weight": "600",
        "monospace": true
      },
      "buttons": {
        "weight": "600",
        "size": "14px"
      }
    },
    "screenLayout": {
      "canvasPercentage": 70,
      "bottomPanelPercentage": 25,
      "hudHeight": 50
    },
    "hudBar": {
      "manaDisplay": {
        "position": "left",
        "content": "Icon + Current/Max + regen/sec",
        "behavior": "animate on change, color cyan"
      },
      "ironDisplay": {
        "position": "center-left",
        "content": "Icon + Amount",
        "behavior": "animate on change, color silver"
      },
      "chargeDisplay": {
        "position": "center-right",
        "content": "Icon + Current/Max",
        "behavior": "fills visually, yellow-orange"
      },
      "waveCounter": {
        "position": "center",
        "content": "Wave X / Next milestone",
        "behavior": "updates on wave change"
      },
      "eliteIndicator": {
        "position": "right-top",
        "content": "Rotating element icon",
        "behavior": "shows current enemy weakness"
      },
      "settingsButton": {
        "position": "right",
        "content": "Gear icon",
        "behavior": "opens settings modal"
      }
    },
    "canvas": {
      "backgroundColor": "#1a1a2e",
      "layers": [
        "background",
        "entities",
        "effects",
        "hudOverlay"
      ],
      "camera": "Fixed top-down view",
      "interactions": {
        "clickRuneSlot": "Cycle element (Fire/Ice/Arcane/Void)",
        "clickCastButton": "Launch crafted spell",
        "clickArena": "Set spell target location",
        "clickCollectible": "Collect mana/iron/crystal",
        "clickOverdriveBar": "Activate elemental overdrive"
      }
    },
    "hudOverlay": {
      "healthBars": {
        "position": "Above each entity",
        "content": "Small colored bar",
        "behavior": "Updates with damage, fades on death (200ms)"
      },
      "floatingDamage": {
        "position": "At hit location",
        "content": "-X in red/white",
        "behavior": "Floats upward 40px over 800ms"
      },
      "waveIndicator": {
        "position": "Top center of canvas",
        "content": "Wave X incoming!",
        "behavior": "Appears 2s before wave, fades"
      },
      "targetReticle": {
        "position": "Around clicked enemy",
        "content": "Dashed circle ring",
        "behavior": "Shows spell homing target"
      },
      "runeSlotHighlights": {
        "position": "Around rune slots",
        "content": "Glow by element",
        "behavior": "Shows currently selected element"
      }
    },
    "bottomPanel": {
      "height": 180,
      "collapsedHeight": 40,
      "tabs": [
        {
          "id": "runes",
          "label": "RUNES",
          "icon": "✨",
          "unlockedAt": "gameStart"
        },
        {
          "id": "upgrades",
          "label": "UPGRADES",
          "icon": "⚡",
          "unlockedAt": "waveComplete >= 3"
        },
        {
          "id": "mastery",
          "label": "MASTERY",
          "icon": "⛇",
          "unlockedAt": "waveComplete >= 3"
        },
        {
          "id": "prestige",
          "label": "PRESTIGE",
          "icon": "✨",
          "unlockedAt": "waveComplete >= 12"
        }
      ],
      "tabAnimation": "Slides in from right over 300ms with fade-in + scale-up effect"
    },
    "tabContent": {
      "runes": {
        "runeSlots": "3-5 slots shown horizontally, click to cycle elements",
        "castButton": "Large centered button, SPACE or click to launch spell",
        "spellPreview": "Shows current combination (e.g., Fire-Ice-Arcane)",
        "slotStates": {
          "available": "Full opacity, bright border, clickable",
          "locked": "50% opacity, dim border, lock icon, hover shows unlock requirement",
          "selected": "Glow animation with pulsing border, shows element icon",
          "hover": "Scale 1.05x, brightness +10%"
        }
      },
      "upgrades": {
        "layout": "2 columns, scrollable",
        "cardStates": {
          "available": "Full opacity, green border (#4caf50), BUY button enabled",
          "cannotAfford": "Full opacity, red border (#f44336), BUY button disabled, shake on click",
          "maxed": "Full opacity, gray border (#606060), BUY button hidden, MAX badge",
          "locked": "50% opacity, dim border (#2a2a4e), lock icon, details hidden"
        }
      },
      "mastery": {
        "fireMastery": "+10% Fire damage per level, makes fire projectiles larger with longer trails",
        "iceMastery": "+10% Ice damage per level, makes ice spells freeze enemies (slow effect)",
        "arcaneMastery": "+10% Arcane damage per level, makes arcane spells home toward targets",
        "voidMastery": "+10% Void damage per level, makes void spells penetrate (full damage to all enemies in line)"
      },
      "prestige": {
        "earnDisplay": "You will earn: +XX Crystal Essence, Current total: YY",
        "resets": [
          "Mana",
          "Iron Shards",
          "Rune slot count",
          "Elemental mastery levels",
          "Current wave"
        ],
        "keeps": [
          "Crystal Essence",
          "Permanent rune slots",
          "Elemental attunement bonuses"
        ],
        "visualChange": "Arena background shifts to new tier, enemies get hue shift"
      }
    },
    "notifications": {
      "notificationArea": {
        "content": "Toast messages",
        "behavior": "Slide in from right, fade after 3s"
      },
      "milestonePopup": {
        "content": "Achievement earned",
        "behavior": "Center screen, dramatic, auto-dismiss 3s"
      }
    },
    "components": {
      "upgradeCard": {
        "layout": "[Icon] [Upgrade Name] [Lvl X] / [Description] / [Effect] / [Cost] [BUY]",
        "affordable": {
          "border": "#4caf50",
          "button": "same, white text"
        },
        "cannotAfford": {
          "border": "#f44336",
          "button": "#2a2a4e, grayed out"
        },
        "maxed": {
          "border": "#606060",
          "badge": "MAX red on card, button hidden"
        },
        "locked": {
          "appearance": "Dimmed 50%, lock or ? icon, no details"
        },
        "hoverAffordable": {
          "effect": "Scale 1.05x over 200ms, subtle shadow"
        },
        "clickAffordable": {
          "effect": "Purchase animation 200ms, card flashes white, currency counts tick down"
        },
        "clickCannotAfford": {
          "effect": "Shake animation, cost flashes red briefly"
        }
      },
      "currencyDisplay": {
        "format": "[Icon] 1,234 (+12.3/s)",
        "numberAnimation": "Count-up 300ms when value changes",
        "rateDisplay": "Per-second rate in smaller text, updates every second",
        "largeNumbers": "K/M/B suffixes",
        "color": "Match accent color for currency",
        "earnedFlash": "Glow/pulse when currency earned from defeating enemies or completing waves"
      },
      "milestoneToast": {
        "appearance": "Slide in from right/top",
        "duration": "3000-5000ms visible",
        "stack": "Multiple toasts stack vertically with 40px gap"
      },
      "prestigePanel": {
        "layout": "Prestige title / You will earn / Current total / Resets / Keeps / Visual change / CANCEL / PRESTIGE!",
        "available": "Button grayed out at Wave 12, clickable at Wave 15",
        "accept": "Celebration effect, transitions to white, loads new run with visual changes",
        "cancel": "Closes modal, returns to game"
      },
      "skillTree": {
        "layout": "CSS Grid, nodes positioned absolutely in grid cells",
        "nodeSize": "80px x 80px",
        "connectionLines": "CSS borders on grid cells, 2px solid lines",
        "nodeStates": {
          "available": "White background, colored border by element, full opacity",
          "maxed": "Gray background, desaturated border, MAX text",
          "locked": "30% opacity, dashed gray border, no details visible",
          "selected": "Pulsing glow effect with scale 1.05x animation"
        }
      },
      "tooltip": {
        "trigger": "Hover (desktop)",
        "position": "20px above element, clamped to viewport",
        "delay": "200ms hover before showing",
        "content": "[Upgrade Name] (Level X) / [Full description] / Current: +Y damage / Next level: +Z damage / Cost: [amount]"
      }
    },
    "controlsPanel": {
      "position": "Bottom center of canvas, just above bottom panel",
      "alwaysVisible": true,
      "layout": "Single row, semi-transparent dark background (#141630 95% opacity)",
      "content": [
        {
          "action": "clickRuneSlot",
          "label": "Click Rune Slot",
          "hotkey": "1-5",
          "description": "Cycle element"
        },
        {
          "action": "castSpell",
          "label": "SPACE / Click CAST",
          "hotkey": "SPACE",
          "description": "Launch spell"
        },
        {
          "action": "clickArena",
          "label": "Click Arena",
          "hotkey": "L-Click",
          "description": "Set target"
        },
        {
          "action": "clickCollectible",
          "label": "Click Resource",
          "hotkey": "none",
          "description": "Collect drops"
        },
        {
          "action": "clickOverdrive",
          "label": "Click Overdrive",
          "hotkey": "O",
          "description": "Activate buff (when full)"
        }
      ]
    },
    "tutorialOverlay": {
      "trigger": "Shows automatically on first page load",
      "dismiss": "Got it! button OR click anywhere outside",
      "persistence": "localStorage to remember dismissal",
      "content": [
        "Click rune slots to craft your spell - Combine elements (Fire, Ice, Arcane, Void)",
        "Press SPACE to launch spell at enemies - Stop them from reaching your rune circle",
        "Click dropped resources to collect them - Use Mana to cast spells, Iron to buy upgrades",
        "Discover spell combinations to unlock upgrades - Survive waves to unlock prestige"
      ],
      "style": "Semi-transparent dark overlay (#1a1a2e 90% opacity), centered modal, large white text (18px), prominent dismiss button",
      "zIndex": "Above everything including canvas"
    },
    "responsive": {
      "minimumWidth": 1280,
      "maximumWidth": "100% viewport",
      "scaling": "Canvas scales to fit available width, bottom panel uses rem-based sizing",
      "collapseBehavior": "Bottom panel can collapse to give Canvas more space, defaults to collapsed on narrow viewports (<600px height)"
    },
    "accessibility": {
      "contrastRatios": "All text meets WCAG AA minimum 4.5:1",
      "focusIndicators": "Visible focus outlines for keyboard navigation (2px solid outline)",
      "screenReader": "Currency amounts have aria-live regions for updates",
      "reducedMotion": "Respect prefers-reduced-motion media query - disable Canvas animations, use static sprites"
    },
    "settings": {
      "notationFormat": {
        "type": "Toggle",
        "default": "Standard",
        "options": [
          "Standard",
          "Scientific"
        ],
        "effect": "Changes number display"
      },
      "animationSpeed": {
        "type": "Slider",
        "default": "1x",
        "range": "0.5x-2x",
        "effect": "Scales all animation durations and Canvas game speed"
      },
      "autoSaveInterval": {
        "type": "Dropdown",
        "default": "30s",
        "options": [
          "15s",
          "30s",
          "60s",
          "off"
        ],
        "effect": "How often game state saves"
      },
      "canvasQuality": {
        "type": "Toggle",
        "default": "High",
        "options": [
          "High",
          "Low"
        ],
        "effect": "Low disables glow effects and particles for performance"
      },
      "hardReset": {
        "type": "Button",
        "confirmation": true,
        "effect": "Wipe all data (cannot undo)"
      },
      "exportSave": {
        "type": "Button",
        "effect": "Copy save string to clipboard"
      },
      "importSave": {
        "type": "Button",
        "effect": "Paste save string from clipboard"
      }
    }
  },
  "config": {
    "canvas": {
      "width": null,
      "height": null,
      "backgroundColor": "#1a1a2e",
      "gridCellSize": 16,
      "layers": [
        "background",
        "entities",
        "effects",
        "hudOverlay"
      ]
    },
    "ui": {
      "tickRate": 20,
      "autoSaveInterval": 30000,
      "theme": "dark",
      "hudHeight": 50,
      "bottomPanelHeight": 180,
      "bottomPanelCollapsedHeight": 40,
      "canvasMinHeight": 400,
      "tabs": [
        {
          "id": "runes",
          "label": "RUNES",
          "icon": "✨",
          "unlockedAt": "gameStart"
        },
        {
          "id": "upgrades",
          "label": "UPGRADES",
          "icon": "⚡",
          "unlockedAt": "waveComplete >= 3"
        },
        {
          "id": "mastery",
          "label": "MASTERY",
          "icon": "⛇",
          "unlockedAt": "waveComplete >= 3"
        },
        {
          "id": "prestige",
          "label": "PRESTIGE",
          "icon": "✨",
          "unlockedAt": "waveComplete >= 12"
        }
      ],
      "notifications": {
        "toastDuration": 3000,
        "toastPosition": "top-right",
        "milestoneDisplayDuration": 5000,
        "stackLimit": 3
      },
      "controls": [
        {
          "action": "clickRuneSlot",
          "label": "Click Rune Slot",
          "hotkey": "1-5",
          "description": "Cycle element"
        },
        {
          "action": "castSpell",
          "label": "SPACE / Click CAST",
          "hotkey": "SPACE",
          "description": "Launch spell"
        },
        {
          "action": "clickArena",
          "label": "Click Arena",
          "hotkey": "L-Click",
          "description": "Set target"
        },
        {
          "action": "clickCollectible",
          "label": "Click Resource",
          "hotkey": "none",
          "description": "Collect drops"
        },
        {
          "action": "clickOverdrive",
          "label": "Click Overdrive",
          "hotkey": "O",
          "description": "Activate buff (when full)"
        }
      ]
    },
    "effects": {
      "particles": {
        "collection": {
          "count": 5,
          "sprite": "spark",
          "lifetime": 500,
          "spread": 20
        },
        "enemyDeath": {
          "count": 5,
          "sprite": "spark",
          "lifetime": 400,
          "spread": 15
        },
        "golemDeath": {
          "count": 30,
          "sprite": "spark",
          "lifetime": 800,
          "spread": 40
        },
        "championDeath": {
          "count": 15,
          "sprite": "spark",
          "lifetime": 600,
          "spread": 25
        },
        "spellcast": {
          "count": 3,
          "sprite": "spark",
          "lifetime": 200,
          "spread": 10
        }
      },
      "floatingText": {
        "duration": 800,
        "riseSpeed": 30,
        "fontSize": 14,
        "fontWeight": "bold",
        "colors": {
          "mana": "#00ffff",
          "ironShards": "#c0c0c0",
          "crystalEssence": "#9932cc",
          "damage": "#ff4444",
          "heal": "#44ff44",
          "xp": "#44aaff"
        }
      },
      "screenFlash": {
        "waveComplete": {
          "color": "#ffffff",
          "opacity": 0.3,
          "duration": 200
        },
        "prestige": {
          "color": "#ffffff",
          "opacity": 1,
          "duration": 500
        },
        "bossSpawn": {
          "color": "#ff0000",
          "opacity": 0.2,
          "duration": 300
        },
        "damageTaken": {
          "color": "#ff4444",
          "opacity": 0.4,
          "duration": 100
        }
      },
      "placementFlash": {
        "duration": 200,
        "color": "#ffffff",
        "opacity": 0.5
      }
    },
    "colorPalette": {
      "background": {
        "primary": "#0f0f1a",
        "secondary": "#1a1a2e",
        "tertiary": "#2a2a4e"
      },
      "canvas": "#1a1a2e",
      "text": {
        "primary": "#e0e0e0",
        "secondary": "#a0a0a0",
        "muted": "#606060"
      },
      "accent1": "#00ffff",
      "accent2": "#4FC3F7",
      "accent3": "#E040FB",
      "success": "#4CAF50",
      "warning": "#FF9800",
      "danger": "#F44336",
      "prestige": "#E040FB"
    }
  }
}

Ui Ux

# Spellforge Arena - UI/UX Design ## Overview Spellforge Arena is a mystical battleground where mages duel by crafting elemental spells in real-time. The visual identity is dark, arcane, and elemental - deep purples and midnight blues accented by glowing orange fire, cyan ice, violet arcane, and black void energies. The Canvas game world dominates the screen, showing the arena floor with a glowing rune circle at bottom center where the player assembles spells, enemies descending from above, and projectiles flying across the screen. The UI is minimal and secondary - a dark bottom panel for upgrades and a top HUD bar for currencies, never obscuring the primary Canvas action. The color palette uses deep mystical blues (#1a1a2e) for the arena background, with elemental accents that shift based on the player's dominant element. Text is light-colored for readability (#e0e0e0) with muted secondary text (#a0a0a0) for less critical information. Primary currency (Mana) uses cyan accents, secondary currency (Iron Shards) uses metallic grays, and prestige currency (Crystal Essence) uses mystical purple - each color-coded for instant recognition. ## Color Palette | Role | Color (hex) | Usage | |------|-------------|-------| | Background (primary) | #1a1a2e | Main background behind Canvas | | Background (secondary) | #141630 | Panels, cards, bottom UI | | Background (tertiary) | #2a2a4e | Disabled states, locked slots | | Canvas background | #1a1a2e | The game world - dark mystical arena floor | | Text (primary) | #e0e0e0 | Main text, labels, values | | Text (secondary) | #a0a0a0 | Secondary labels, descriptions | | Text (muted) | #606060 | Disabled buttons, unavailable items | | Accent 1 (Mana) | #00ffff | Primary actions, Mana currency | | Accent 2 (Iron) | #c0c0e0 | Secondary actions, Iron Shards currency | | Accent 3 (Charge) | #ffcc00 | Tertiary elements, Elemental Charge | | Success | #4caf50 | Affordable, completed, positive feedback | | Warning | #ff9800 | Almost affordable, attention needed | | Danger | #f44336 | Cannot afford, low mana warning | | Prestige | #9932cc | Prestige currency, prestige UI elements | | Spell Fire | #ff6b354 | Fire element - orange glow | | Spell Ice | #00ffff | Ice element - cyan blue | | Spell Arcane | #bf5eff | Arcane element - violet purple | | Spell Void | #1a1a2e | Void element - black with white rim | ## Typography - **Font family**: 'Cinzel', 'Segoe UI', Tahoma, sans-serif (system fonts) - **Headings**: Bold 600-700, sizes: 24px (game title), 18px (section headers), 14px (card titles) - **Body text**: Normal 400, size: 13px (descriptions, labels) - **Numbers/currencies**: Normal 600, monospace option for aligned digits - **Buttons**: Semibold 600, size: 14px ## Screen Layout ### Master Layout ``` +--------------------------------------------------+ | [HUD Bar - currencies, rates, wave/round info] | +--------------------------------------------------+ | | | [CANVAS - Main Game World] | | (70% of screen height - ~450px at 720p) | | Animated sprites, entities, effects, | | rune circle at bottom, enemy spawn from top | | | +--------------------------------------------------+ | [Bottom Panel - rune slots, cast button, upgrade tabs] | | (25% of screen height - ~180px at 720p) | +--------------------------------------------------+ ``` ### HUD Bar (Always Visible, overlays top of Canvas) | Element | Position | Content | Behavior | |---------|----------|---------|----------| | Mana display | Left | Icon 💧 + Current/Max + regen/sec | Cyan color, animates on change, shows "20/100" then counts up | | Iron Shards display | Center-left | Icon ⚙️ + Amount | Silver-gray color, animates on change | | Elemental Charge display | Center-right | Icon ⚡ + Current/Max | Yellow-orange color, fills visually, empties on overdrive | | Wave counter | Center | Wave X / Next milestone | White text, updates on wave change | | Elite indicator | Right-top | Rotating element icon (when Champion active) | Shows current enemy weakness | | Settings button | Far right | Gear icon ⚙️ | Opens settings modal | ### Game World Canvas - **Dimensions**: 100% of viewport width, flexible height (remaining space after HUD and bottom panel) - **Background**: Solid color #1a1a2e (dark mystical blue), with subtle pentagram pattern overlay that pulses with current dominant element - **Layers** (drawn in order): 1. Background layer (arena floor - stone texture with glowing pentagram lines) 2. Entity layer (enemies, projectiles, collectible sprites) 3. Effect layer (damage numbers, death particles, spell trails) 4. HUD overlay layer (health bars above entities, selection reticle, rune circle glow) - **Camera**: Fixed top-down view. Arena is static, entities move within frame. No scrolling. - **Click/touch interaction (CRITICAL)**: - **Click rune slots** (bottom of Canvas): Cycles through elements (Fire → Ice → Arcane → Void) - **Click CAST button** (bottom center): Launches crafted spell toward last clicked target - **Click on arena**: Sets spell target location. Creates targeting reticle at clicked position - **Click collectible sprites**: Collects dropped mana/iron/crystal sprites within radius - **Click overdrive bar** (when full): Activates 3x damage buff for next spell ### Entity Visual Specs For EVERY entity type from idea.md, provide a state machine diagram and a CONFIG entry. #### Entity State Machine Template Each entity type MUST have a state machine diagram showing all visual states and transitions: ```mermaid stateDiagram-v2 [*] --> Spawning: created Spawning --> Idle: spawn animation complete (300ms) Idle --> Active: player/cursor interaction available Active --> Dying: hp <= 0 Dying --> [*]: death animation complete (500ms) note right of Spawning Animation: scale 0→1 Duration: 300ms Invulnerable: true end note note right of Idle Frames: 0-1 Frame duration: 500ms Facing: last direction Animation: bob (gentle vertical movement) end note note right of Active Multiple states possible based on entity type: - Moving: Walking/flying toward target - Attacking: Combat/ability in progress - Dying: Playing death animation end note note right of Dying Animation: fade opacity 1→0 Duration: 500ms Spawns: death particles (spark sprite × 3-5) On complete: remove from entity list end note ``` Create one diagram per entity type (player units, enemy types, projectiles, collectibles). Customize states for each — e.g., structures don't have Moving, projectiles don't have Idle. #### Entity Interaction Diagram Show how entities interact with each other on Canvas: ```mermaid flowchart LR subgraph Player Entities Spell["Spell Projectile\n(fires at enemies)"] TargetReticle["Target Reticle\n(player click on arena)"] end subgraph Enemy Entities Wisp["Wisp Enemy\n(moves to rune circle)"] Guardian["Guardian Enemy\n(moves to rune circle)"] Golem["Golem Boss\n(slow, high HP)"] Champion["Elite Champion\n(moves to rune circle)"] end subgraph Collectibles ManaFragment["Mana Fragment\n(+3 Mana)"] IronShard["Iron Shard\n(+5 Iron)"] CrystalEssence["Crystal Essence\n(+1 Essence)"] ElementSprite["Element Sprite\n(+2 Charge)"] end Spell -->|"hits"| Wisp Spell -->|"hits"| Guardian Spell -->|"hits"| Golem Spell -->|"hits"| Champion Wisp -->|"reaches rune circle"| PlayerDamage Guardian -->|"reaches rune circle"| PlayerDamage Golem -->|"reaches rune circle"| PlayerDamage Champion -->|"reaches rune circle"| PlayerDamage TargetReticle -->|"follows mouse"| Spell Wisp -.->|"on death → spawns"| ManaFragment Guardian -.->|"on death → spawns"| IronShard Golem -.->|"on death → spawns"| IronShard Champion -.->|"on death → spawns"| IronShard Golem -.->|"on death → spawns"| CrystalEssence Champion -.->|"on death → spawns"| CrystalEssence ElementSprite -.->|"periodic spawn"| Self ManaFragment -->|"player clicks → collect"| Player IronShard -->|"player clicks → collect"| Player CrystalEssence -->|"player clicks → collect"| Player ElementSprite -->|"player clicks → collect"| Player ``` ### HUD Overlay (drawn ON Canvas) | Element | Position | Content | Behavior | |---------|----------|---------|----------| | [Entity health bars] | Above each entity | Small colored bar | Updates with damage, fades on death (200ms fade) | | [Floating damage numbers] | At hit location | "-15" in red/white | Floats upward 40px over 800ms | | [Wave indicator] | Top center of canvas | "Wave 5 incoming!" | Appears 2s before wave, fades over 1s | | [Target reticle] | Around clicked enemy | Dashed circle ring | Shows which enemy spell will home toward | | [Rune slot highlights] | Around rune slots | Glow by element | Shows currently selected element in each slot | | [Charge meter fill animation] | Above charge bar | Smooth fill | Animates from 0 to target value over 200ms | | [Overdrive aura] | Around rune circle when active | Pulsing glow | 3x damage active - shows for 5s | ### Bottom Panel (Upgrade/Management Area) ``` +--------------------------------------------------+ | [Tab 1: RUNES] [Tab 2: UPGRADES] [Tab 3: MASTERY] [Tab 4: PRESTIGE] [COLLAPSE] | +--------------------------------------------------+ | | | [Active Tab Content Area] | | - Rune slots display (3-5 slots shown horizontally) | | - CAST button (large, centered) | | - Current spell preview (shows combination) | | - Upgrade cards, skill tree, or prestige panel | | | +--------------------------------------------------+ ``` - **Height**: 180px at 720p viewport (25% of screen) - **Collapse button**: Arrow icon ▲ at left edge to minimize panel (gives more Canvas space) - **When collapsed**: Only tab bar visible (single row of icons/labels), panel height 40px ### Navigation / Tab Bar | Tab | Icon/Label | Unlocked At | Content | |-----|------------|-------------|---------| | [RUNES] | 🌟 Runes | Game start | 3-5 rune slots, cast button, spell preview | | [UPGRADES] | ⬆️ Upgrades | Wave 3 complete | Elemental masteries, spell damage, mana regen | | [MASTERY] | 🔱 Mastery | Wave 3 complete | Fire, Ice, Arcane, Void mastery levels | | [PRESTIGE] | ✨ Prestige | Wave 12 complete | Permanent upgrades, prestige button | **Tab appearance animation**: New tab slides in from right over 300ms with fade-in + slight scale-up effect. Active tab gets brighter background. ### Tab Contents #### Tab 1: RUNES ``` +---------------------------------------+ | [Rune Slot Display] | | +----------------+--------+--------------+ | | | [Slot 1] | [Slot 2] | [Slot 3] | [Slot 4] | [Slot 5] | | +---+-------+---+-------+---+-------+---+ | | | 🔥/❄️/✨/⚫ | Click to cycle | Fire | Ice | Arcane | Void | (locked) | | +---+-------+---+-------+---+-------+---+ | | | Current spell: Fire-Ice-Arcane (example) | | +---------------------------------------+--------------+ | | | +----------------+-------------------------+--------------+ | | [CAST BUTTON] (large, centered) | | | SPACE or click to launch spell | | | Target reticle shows last clicked arena location | | +---------------------------------------+--------------+ | | +---------------------------------------+ ``` **Rune Slot states**: - Available: Full opacity, bright border, clickable - Locked: 50% opacity, dim border, lock icon overlay, hover shows "Unlock at Wave X" - Selected: Glow animation (pulsing border), shows element icon - Hover: Scale 1.05x, brightness +10% #### Tab 2: UPGRADES ``` +---------------------------------------+ | [Upgrade Cards - 2 columns, scrollable] | | +--------+--------+--------------+ | | | [Fire Mastery] | [Ice Mastery] | [Arcane Mastery] | [Void Mastery] | | +---+-----------+------+---------+------+---------+---+ | | Level: 3/10 | Level: 0/10 | Level: 2/10 | Level: 1/10 | (locked) | | | +50% dmg | +50% dmg | +50% dmg | +50% dmg | | | Cost: 86 Iron | Cost: 30 Iron | Cost: 30 Iron | (locked) | | | [BUY] | [BUY] | [BUY] | [MAX] | [BUY] | | +---+-----------+------+---------+------+---------+---+ | | [Spell Damage] | [Mana Mastery] | [Rune Slot 4] | [Rune Slot 5] | | | Level: 2/15 | Level: 5/5 | (locked) | (locked) | | | +10% all | +1 regen/s | Cost: 100 Iron | Cost: 500 Iron | | | [BUY] | [BUY] | [LOCK] | [LOCK] | [BUY] | | +---------------------------------------+--------------+ | | +---------------------------------------+ ``` **Upgrade Card states**: - Available: Full opacity, green border (#4caf50), BUY button enabled - Cannot afford: Full opacity, red border (#f44336), BUY button disabled with shake animation on click - Maxed: Full opacity, gray border (#606060), BUY button hidden, MAX badge - Locked: 50% opacity, dim border (#2a2a4e), lock icon, details hidden #### Tab 3: MASTERY Same layout as UPGRADES but shows elemental mastery levels with different effects: - Fire Mastery: +10% Fire damage per level, makes fire-themed spell projectiles larger with longer trails - Ice Mastery: +10% Ice damage per level, makes ice spells freeze enemies (slow effect) - Arcane Mastery: +10% Arcane damage per level, makes arcane spells home toward targets - Void Mastery: +10% Void damage per level, makes void spells penetrate (full damage to all enemies in line) #### Tab 4: PRESTIGE ``` +---------------------------------------+ | [PRESTIGE PANEL] | | +----------------+-----------------------------+ | | | You will earn: +XX Crystal Essence | | | Current total: YY Crystal Essence | | | | | | RESETS: | | | - [item 1] | | | - [item 2] | | | - [item 3] | | | - [item 4] | | | | | | KEEPS: | | | - [permanent rune slot +1] | | | - [elemental attunement +10%] | | | - [mana cap +20] | | | | | | [VISUAL CHANGE:] | | | - Arena becomes more ornate | | | - Enemies get hue shift +30 | | | | | | [CANCEL] [PRESTIGE!] | +---------------------------------------+ ``` Prestige panel appears as modal overlay, dims background behind it. ### Notifications Area | Element | Content | Behavior | |---------|---------|----------| | [Notification area] | Toast messages | Slide in from right, fade after 3s | | [Milestone popup] | Achievement earned | Center screen, dramatic, auto-dismiss 3s | ## Component Specifications ### Upgrade Card ``` +----------------------------------+ | [Icon: 🔥] [Upgrade Name] [Lvl X] | +----------------------------------+ | [Effect: +50% Fire damage] | | [Cost: 86 Iron] [BUY] | +----------------------------------+ ``` - **Affordable state**: Border #4caf50 (success green), button background same, BUY button text "BUY" in white - **Cannot afford state**: Border #f44336 (danger red), button background #2a2a4e (disabled), BUY button text grayed out - **Maxed state**: Border #606060 (muted gray), "MAX" badge red on card, BUY button hidden - **Locked state**: Entire card dimmed to 50% opacity, "🔒" or "?" icon instead of details, no BUY button - **Hover (affordable)**: Scale 1.05x over 200ms, subtle shadow - **Click (affordable)**: Purchase animation over 200ms, card flashes white, currency counters tick down ### Currency Display (HUD) ``` [💧] 1,234 (+12.3/s) ``` - **Number animation**: Count-up animation when value changes, duration 300ms - **Rate display**: Per-second rate in smaller gray text below main number - **Large numbers**: When switching to K/M/B suffixes, animate the transition - **Color**: Match accent color for this currency (Mana = cyan) - **Earned by gameplay flash**: Brief glow/pulse on currency icon when earned from killing enemies or completing waves, distinct from passive regen ticks ### Milestone/Achievement Toast ``` +----------------------------------+ | ★ [Achievement Name]! | +----------------------------------+ | [Description text] | | [+Reward] | +----------------------------------+ ``` - **Appearance**: Slide in from right edge over 300ms, stays for 3s, slides out - **Duration**: 3000ms visible - **Stack behavior**: Multiple toasts stack vertically with 40px gap between them - **Colors**: Success = green border, Achievement = gold border ### Prestige Panel [Layout for prestige confirmation screen] ``` +----------------------------------+ | ⟳ [PRESTIGE TITLE] | | | | You will earn: [+XX Crystal Essence] | | Current total: [YY Crystal Essence] | | | | RESETS: | | - [item 1] [item 2] | | - [item 3] [item 4] | | - [item 5] [item 6] | | | | VISUAL CHANGE: | | - Arena background shifts to new tier | | - Enemies get hue shift based on tier | | | | [CANCEL] [PRESTIGE!] | +----------------------------------+ ``` - **Prestige available**: Button appears grayed out at Wave 12, becomes clickable at Wave 15 - **Accept action**: Shows celebration effect, transitions to white, loads new run with visual changes - **Cancel action**: Closes modal, returns to game ### Skill Tree Renderer - **Layout approach**: CSS Grid using display:grid, nodes positioned absolutely within grid cells - **Node size**: 80px × 80px per node - **Connection lines**: CSS borders on grid cells, 2px solid lines connecting related nodes - **Node states**: - Available: White background, colored border matching element type, full opacity - Maxed: Gray background, desaturated border, "MAX" text - Locked: 30% opacity, dashed gray border, no details visible - Selected: Pulsing glow effect with scale 1.05x animation ### Tooltip ``` +----------------------------------+ | [Upgrade Name] (Level X) | +----------------------------------+ | [Full description] | | Current: +Y damage | | Next level: +Z damage | | Cost: [amount] | +----------------------------------+ ``` - **Trigger**: Hover (desktop) - **Position**: 20px above element, centered horizontally, clamped to viewport edges - **Delay**: 200ms hover before showing - **Style**: Semi-transparent dark background (#1a1a2e with 90% opacity), white text, 12px font ## UI Event Flow Diagrams ### Player Interaction → Canvas → UI Flow ```mermaid sequenceDiagram actor Player participant Canvas as Canvas participant RuneSystem as RuneSystem participant EventBus as EventBus participant UI as HUD/Panels Note over Player,UI: Player clicks rune slot to change element Player->>Canvas: click rune slot at (x, y) Canvas->>RuneSystem: runeSlotClicked(slotIndex) RuneSystem->>RuneSystem: cycleElement(slotIndex) RuneSystem->>EventBus: emit('rune-changed', {slotIndex, newElement}) EventBus->>Canvas: updateSlotVisual(slotIndex, newElement) Canvas->>Canvas: slot shows glow animation (200ms) EventBus->>UI: updateSpellPreview() Note over Player,UI: Player clicks arena to set target Player->>Canvas: click arena at (targetX, targetY) Canvas->>EventBus: emit('target-set', {x, y}) EventBus->>Canvas: showTargetReticle(targetX, targetY) Canvas->>Canvas: create reticle sprite at target, pulse animation Note over Player,UI: Player presses SPACE to cast spell Player->>RuneSystem: pressSpace() or clickCastButton() RuneSystem->>EventBus: emit('spell-cast-request') EventBus->>Canvas: validateSpellComposition() alt Invalid composition EventBus->>UI: showInvalidWarning() EventBus->>Canvas: shakeRuneCircle() end EventBus->>EventBus: emit('spell-cast', {elements, target}) EventBus->>Canvas: spawnProjectile(elements, target) Canvas->>Canvas: projectile spawns from rune circle with animation EventBus->>UI: deductMana(spellCost) EventBus->>UI: floatingText("-{cost}💧", runeCircle, cyan) ``` ```mermaid sequenceDiagram actor Player participant Canvas as Canvas participant EntitySystem as EntitySystem participant EventBus as EventBus participant UI as HUD/Panels Note over Player,UI: Enemy dies → drops → player collects EntitySystem->>EntitySystem: enemy.hp <= 0 EntitySystem->>Canvas: death animation (fade + spark particles) EntitySystem->>EventBus: emit('enemy-killed', {type, position, reward}) EventBus->>Canvas: spawnCollectible({type, position, value}) Canvas->>Canvas: collectible bob animation Player->>Canvas: clicks collectible (within radius) Canvas->>EventBus: emit('collectible-collected', {type, value, position}) EventBus->>UI: floatingText("+{value}{icon}", position, color) EventBus->>UI: currency count-up animation (300ms) EventBus->>Canvas: removeCollectible() EventBus->>UI: gameplay-earned flash/pulse on currency display ``` ## UI State Machine ```mermaid stateDiagram-v2 [*] --> Loading: page load Loading --> Playing: assets loaded, tutorial dismissed state Playing { [*] --> PreWave: between waves PreWave --> WaveActive: countdown complete (3s) WaveActive --> PreWave: wave cleared WaveActive --> GameOver: player died state PreWave { [*] --> Combat: player can interact Combat --> [*]: Wave spawn starts [*] --> Idle: no active targets } Playing --> Prestige: player clicks prestige Prestige --> Playing: new run starts Playing --> SettingsModal: gear icon clicked SettingsModal --> Playing: modal closed GameOver --> Playing: restart } note right of PreWave UI: "Wave {n} incoming!" (3s countdown) Canvas: spawn indicators pulse at top Player: can interact with rune slots, no spells end note note right of WaveActive Enemies spawning/moving Player casts spells at enemies Collectibles spawn and can be clicked Charge meter builds from spell chains end note note right of GameOver Canvas: red overlay "DEFEATED" UI: "Retry?" button End note ``` ## Feedback Systems ### Visual Feedback Catalog | Action | Canvas Feedback | UI Feedback | Duration | |--------|----------------|-------------|----------| | Enemy defeated | Death animation (fade + spark particles), floating "+5 ⚙️" | Sprite fades over 300ms, particles burst (5 sprites, 400ms) | 300ms | | Wave completed | Brief screen flash, all enemies gone | Toast "Wave X Complete!" +3s, wave counter increments | 1s | | Purchase upgrade | Upgraded entity glows briefly on Canvas (if applicable) | Card flashes green, cost deducted animation | 300ms | | Cannot afford click | N/A | Card shakes, cost flashes red | 200ms | | New unlock | N/A | Tab glow/pulse, notification dot, toast appears | Until clicked | | Prestige | Canvas transition effect (fade to white, new world fades in) | Screen flash, transition animation | 1-2s | | Spell cast | Projectile spawns from rune circle with trail | Mana deducts, floating "-X 💧" | 200ms | | Collectible collected | Sprite scales up and disappears, particles burst | Currency counter pulses up | 300ms | | Entity takes damage | Sprite flashes white briefly | N/A | 200ms | | Overdrive activated | Rune circle gets intense elemental glow | Charge bar empties with burst | 500ms | ### Number Formatting Rules | Range | Format | Example | |-------|--------|---------| | 0 - 999 | Whole number | 742 | | 1,000 - 999,999 | With commas | 1,234 | | 1M - 999.9M | Suffix | 1.5M | | 1B - 999.9B | Suffix | 42.3B | | 1T+ | Suffix | 1.2T | | Rates (/sec) | 1 decimal | +12.3/s | | Damage numbers (Canvas) | Whole number | -15 | ### Progress Bars - **Style**: Rounded corners (6px border-radius), smooth fill animation (transition: background-color 0.3s ease-out), no label - **Color**: Changes based on percentage (green > 50%, yellow 30-50%, red < 30%) - **Label**: Percentage only (no "current/max" text) ## Controls Panel (MANDATORY - Always Visible) The game MUST have a permanently visible controls panel showing all player interactions. This is NOT optional. ### Controls Panel Layout ``` +--------------------------------------------------+ | CONTROLS: [Click Rune Slot] | [SPACE Cast] | [Click Target] | +--------------------------------------------------+ ``` - **Position**: Bottom center of canvas, just above bottom panel (or integrated into bottom panel top edge) - **Always visible**: Never hidden behind a tab or menu - **Content**: List every player action with its trigger - **Style**: Compact single-row, semi-transparent dark background (#141630 with 95% opacity), light white text, monospace for hotkeys - **Responsive**: If space is tight, use icon + hotkey shorthand (e.g., "🌟 Click | ⚡ Cast") ### Controls Panel Content for Spellforge Arena: | Action | Trigger | Description | |--------|----------|------------| | Click Rune Slot | Click on rune slot at bottom of Canvas | Cycles through Fire🔥/Ice❄️/Arcane✨/Void⚫ elements | | SPACE / Click CAST | Press SPACE or click CAST button | Launches crafted spell toward target | | Click Arena | Click anywhere on arena (Canvas) | Sets spell target location, shows targeting reticle | | Click Resource | Click Mana/Iron/Crystal sprites on Canvas | Collects dropped resources | | Click Overdrive Bar | Click charge bar when full (⚡ 50+) | Activates 3x damage buff for next spell | ## Getting Started Overlay (MANDATORY - Shows on First Load) The game MUST show a "How to Play" overlay on first load. This appears ONCE, centered on screen, over Canvas. ### Tutorial Overlay Layout ``` +---------------------------------------+ | HOW TO PLAY | | | | • Click rune slots to craft your spell | | • Combine elements (Fire, Ice, Arcane, Void) | | • Press SPACE to launch spell at enemies | | • Stop enemies from reaching your rune circle | | • Click dropped resources to collect them | | • Discover spell combinations to unlock upgrades | | | | [GOT IT!] | +---------------------------------------+ ``` - **Trigger**: Shows automatically on first page load - **Dismiss**: "GOT IT!" button OR click anywhere outside - **Persistence**: Use localStorage to remember dismissal. Don't show again after first dismiss - **Content**: 4 concise bullet points - **Style**: Semi-transparent dark overlay (#1a1a2e with 90% opacity), centered modal, large readable white text (18px), prominent dismiss button - **Z-index**: Above everything including Canvas ## Responsive Considerations - **Minimum width**: 1280px - **Maximum width**: 100% of viewport - **Scaling approach**: Canvas scales to fit available width; bottom panel uses rem-based sizing (1rem = 16px at default) - **Panel collapse behavior**: Bottom panel can be collapsed to give Canvas more space. On narrow viewports (< 600px height), defaults to collapsed. ## Accessibility - **Contrast ratios**: All text meets WCAG AA minimum 4.5:1 (light text on dark backgrounds) - **Focus indicators**: Visible focus outlines for keyboard navigation (2px solid outline) - **Screen reader**: Currency amounts have aria-live regions for updates (e.g., <span aria-live="polite">20</span>) - **Reduced motion**: Respect prefers-reduced-motion media query - disable Canvas animations, use static sprites ## Settings Panel | Setting | Type | Default | Effect | |---------|------|---------|--------| | [Notation format] | Toggle | Standard | Standard | Changes number display (1,234 vs 1.2k) | | [Animation speed] | Slider (0.5x-2x) | 1x | Scales all animation durations and Canvas game speed | | [Auto-save interval] | Dropdown | 30s | How often game state saves (15s, 30s, 60s, off) | | [Canvas quality] | Toggle | High | High | Low disables glow effects and particles for performance | | [Hard reset] | Button (with confirmation) | N/A | Wipes all data (cannot undo) | | [Export save] | Button | N/A | Copies save string to clipboard (base64) | | [Import save] | Button | N/A | Pastes save string from clipboard | ## CONFIG Spec: canvas, ui, and effects Sections ```javascript // Canvas and UI Configuration for Spellforge Arena CONFIG.canvas = { width: null, // Null = 100% of viewport height: null, // Calculated: viewportHeight - hudHeight - bottomPanelHeight backgroundColor: '#1a1a2e', // Dark mystical blue gridCellSize: 16, // For reference (not used in spellforge gameplay) layers: ['background', 'entities', 'effects', 'hudOverlay'], }; CONFIG.ui = { tickRate: 20, // UI updates per second autoSaveInterval: 30000, // ms theme: 'dark', hudHeight: 50, // px bottomPanelHeight: 180, // px at 720p viewport (25%) bottomPanelCollapsedHeight: 40, // px when collapsed (just tab bar) canvasMinHeight: 400, // px minimum canvas height tabs: [ { id: 'runes', label: 'RUNES', icon: '🌟', unlockedAt: 'gameStart' }, { id: 'upgrades', label: 'UPGRADES', icon: '⬆️', unlockedAt: 'waveComplete >= 3' }, { id: 'mastery', label: 'MASTERY', icon: '🔱', unlockedAt: 'waveComplete >= 3' }, { id: 'prestige', label: 'PRESTIGE', icon: '✨', unlockedAt: 'waveComplete >= 12' }, ], notifications: { toastDuration: 3000, // ms toastPosition: 'top-right', milestoneDisplayDuration: 5000, // ms stackLimit: 3, // max simultaneous toasts }, controls: [ { action: 'clickRuneSlot', label: 'Click Rune Slot', hotkey: '1-5', description: 'Cycle element' }, { action: 'castSpell', label: 'SPACE / Click CAST', hotkey: 'SPACE', description: 'Launch spell' }, { action: 'clickArena', label: 'Click Arena', hotkey: 'L-Click', description: 'Set target' }, { action: 'clickCollectible', label: 'Click Resource', hotkey: 'none', description: 'Collect drops' }, { action: 'clickOverdrive', label: 'Click Overdrive', hotkey: 'O', description: 'Activate buff (when full)' }, ], }; CONFIG.effects = { particles: { collection: { count: 5, sprite: 'spark', lifetime: 500, spread: 20 }, enemyDeath: { count: 5, sprite: 'spark', lifetime: 400, spread: 15 }, golemDeath: { count: 30, sprite: 'spark', lifetime: 800, spread: 40 }, championDeath: { count: 15, sprite: 'spark', lifetime: 600, spread: 25 }, spellcast: { count: 3, sprite: 'spark', lifetime: 200, spread: 10 }, }, floatingText: { duration: 800, // ms riseSpeed: 30, // px/sec fontSize: 14, fontWeight: 'bold', colors: { mana: '#00ffff', // Cyan ironShards: '#c0c0e0', // Silver-gray crystalEssence: '#9932cc', // Purple damage: '#ff4444', // Red heal: '#44ff44', // Green xp: '#44aaff', // Yellow }, }, screenFlash: { waveComplete: { color: '#ffffff', opacity: 0.3, duration: 200 }, prestige: { color: '#ffffff', opacity: 1.0, duration: 500 }, bossSpawn: { color: '#ff0000', opacity: 0.2, duration: 300 }, damageTaken: { color: '#ff4444', opacity: 0.4, duration: 100 }, }, placementFlash: { duration: 200, color: '#ffffff', opacity: 0.5 }, }; CONFIG.colorPalette = { background: { primary: '#1a1a2e', secondary: '#141630', tertiary: '#2a2a4e' }, canvas: '#1a1a2e', text: { primary: '#e0e0e0', secondary: '#a0a0a0', muted: '#606060' }, accent1: '#00ffff', // Mana - cyan accent2: '#c0c0e0', // Iron Shards - silver accent3: '#ffcc00', // Elemental Charge - yellow success: '#4caf50', warning: '#ff9800', danger: '#f44336', prestige: '#9932cc', spellFire: '#ff6b354', spellIce: '#00ffff', spellArcane: '#bf5eff', spellVoid: '#1a1a2e', }; ``` ## Engagement Self-Audit (MANDATORY) Before finalizing your design, conduct this engagement audit: ### Is This Actually A Game? (MOST CRITICAL) - ✅ Can you describe 30 seconds of gameplay without mentioning numbers, currencies, or upgrades? - YES: Player clicks rune slots cycling through Fire/Ice/Arcane elements, watches spell projectiles fly toward enemies, sees impact effects, clicks collectible sprites - all visual gameplay - ✅ Does player interact with Canvas directly (clicking, placing, directing) at least every 10 seconds? - YES: Player constantly clicking rune slots (every 2-3 seconds to assemble spell), clicking arena to set target (every 3-5 seconds), or clicking collectibles (continuously) - ✅ If you removed all upgrade panels, is there still a recognizable game on Canvas? - YES: Even without upgrades, the core rune-crafting spell-casting gameplay is visually engaging - projectiles flying, enemies moving, explosions happening - ✅ Would a bystander watching over player's shoulder understand what's happening? - YES: Clear visual language - colored projectiles (orange=fire, blue=ice, purple=arcane), distinct enemy types (ghost=wisp, knight=guardian), glowing rune circle at bottom Answer: **YES, this is a real game with Canvas-based visual gameplay.** ### Feedback Loop Completeness | Action | Canvas Feedback (required) | UI Feedback (required) | |--------|---------------------------|----------------------| | Cast spell | Projectile spawns with trail effect | Mana counter animates down with floating "-X 💧" | | Enemy dies | Death animation + particles | Currency sprite drops, counter pulses up | | Buy upgrade | N/A (spell upgrades don't affect Canvas entities directly) | Card flashes green, cost deducted | | Wave complete | Screen flash, wave counter increments | Toast appears | | Collect resource | Sprite scales up and disappears | Currency counter pulses up | | Cannot afford | N/A | Card shakes, cost flashes red | | New unlock | Tab glows/pulses | Toast notification | All major actions have BOTH Canvas and UI feedback where applicable. ### Reward Visibility Check At any moment, player should see 2-3 things they're working toward: - ✅ Next affordable upgrade (cost visible, progress bar on card) - ✅ Next unlock threshold (e.g., "Unlock at Wave 5" shown on locked cards) - ✅ Current production rate (Mana regen shown as "+12.3/s" in HUD) - ✅ Wave progress (Wave X of Y shown in HUD) ### Variable Reward Check - ✅ Wave completion rewards vary by wave number (10×wave Mana) - ✅ Milestones give diverse rewards (new spell combinations, rune slots, elemental charge mechanics) - ✅ First 3 waves have guaranteed unlocks to keep progression flowing ## Entity State Machines ### Spell Projectile ```mermaid stateDiagram-v2 [*] --> Spawning: spell cast Spawning --> Flying: launch from rune circle (100ms) Flying --> Impact: collision with enemy Flying --> Expired: lifetime exceeded (2s timeout) Impact --> [*]: deal damage, spawn particles, remove note right of Spawning Animation: scale 0→1 from rune circle Duration: 100ms Color: based on elemental composition end note note right of Flying Speed: 300px/sec (adjusted by elements) Trail: particle effect based on element Rotation: Fire/Arcane = rotate, Ice/Void = none end note note right of Impact Triggers: enemy.takeDamage() Spawns: 5 spark particles Visual: burst effect at impact point end note note right of Expired Fades out: opacity 1→0 over 500ms On complete: remove from entity list end note ``` ### Enemy: Wisp ```mermaid stateDiagram-v2 [*] --> Spawning: wave spawn trigger Spawning --> Active: fade in (200ms), spawn animation complete Active --> Moving: toward rune circle (zigzag pattern) Moving --> Dying: hp <= 0 Dying --> [*]: death complete (300ms) note right of Active Sprite: ghost (cyan/white) Animation: 4 frames, 200ms per frame Movement: zigzag toward bottom Speed: 80px/sec (fast) HP: 10 end note note right of Dying Animation: fade opacity 1→0 Duration: 300ms Spawns: mana fragment collectible On complete: remove from entity list end note ``` ### Enemy: Guardian ```mermaid stateDiagram-v2 [*] --> Spawning: wave spawn trigger Spawning --> Active: scale in (250ms), spawn animation complete Active --> Moving: toward rune circle (straight line) Moving --> Fighting: in spell range Fighting --> Moving: target dead/out of range Moving --> Dying: hp <= 0 Dying --> [*]: death complete (400ms) note right of Active Sprite: knight (steel gray armor) Animation: 4 frames, 200ms per frame Movement: straight toward bottom Speed: 50px/sec (medium) HP: 30 end note note right of Fighting Triggers: attack animation (frame 2-3) Spawns: projectile every 500ms end note note right of Dying Animation: fade + metallic flash Duration: 400ms Spawns: iron shard collectible (guaranteed) On complete: remove from entity list end note ``` ### Enemy: Golem (Boss) ```mermaid stateDiagram-v2 [*] --> Spawning: wave 5 boss trigger Spawning --> Teased: 3s countdown, "⚠️ BOSS INCOMING" toast Teased --> Active: dramatic spawn (500ms) + screen flash Active --> Moving: slow march toward rune circle Active --> Dying: hp <= 0 Dying --> [*]: death complete (800ms) note right of Teased UI: "⚠️ BOSS INCOMING" toast for 3s Canvas: spawn indicators pulse at top end note note right of Active Sprite: slime (brown/gray, scale 2.0x) Animation: 2 frames, 400ms per frame (very slow) Movement: straight toward bottom Speed: 20px/sec (very slow) HP: 150 (massive) Scale: 2.0x (48×48px) end note note right of Dying Animation: fade opacity 1→0 Duration: 800ms Spawns: iron shard collectibles (3× guaranteed) + crystal essence (30%) Screen shake: 5px over 100ms On complete: wave complete check end note ``` ### Enemy: Elite Champion ```mermaid stateDiagram-v2 [*] --> Spawning: wave 7+ champion trigger Spawning --> Teased: 5s countdown Teased --> Active: teleport in (400ms) + purple flash Active --> Moving: purposeful walk toward rune circle Active --> Casting: special ability every 5s Casting --> Moving: ability complete Active --> Dying: hp <= 0 Dying --> [*]: death complete (600ms) note right of Teased UI: "Champion approaching" toast Canvas: warning pulse end note note right of Active Sprite: wizard (red/purple, scale 1.2x) Animation: 4 frames, 200ms per frame Movement: straight toward bottom Speed: 60px/sec (fast) HP: 80 Scale: 1.2x (38×38px) Has health bar: 40px wide, 4px tall, -8px y-offset end note note right of Casting Ability 1: Summon 2 Wisps at top Ability 2: Fire counter-spell toward player end note note right of Dying Animation: fade with energy release Duration: 600ms Spawns: iron shard collectibles (4× guaranteed) + crystal essence (60%) On complete: wave advancement check end note ``` ### Collectible: Mana Fragment ```mermaid stateDiagram-v2 [*] --> Spawning: enemy death Spawning --> Active: spawn animation (200ms) Active --> Collected: player clicks within 20px Active --> Expired: lifetime 8s exceeded Active --> Attracting: magnetism unlocked, within 100px Collected --> [*]: add Mana + floating "+3" Expired --> [*]: fade out (300ms) Attracting --> Collected: reaches player position Attracting --> Expired: lifetime exceeded note right of Spawning Sprite: spark (cyan, scale 1.2) Position: at enemy death location Animation: scale 0→1 (200ms) Spawn: with burst effect (5 particles) end note note right of Active Visual: cyan bob animation, glow Clickable radius: 20px Shows "+3" on hover Drifts slowly downward (10px/sec) Sprite: spark (cyan, scale 1.2) Magnetism: when active, floats toward player at 150px/sec end note note right of Collected Triggers: currency.add('mana', 3) Triggers: floatingText("+3💧", cyan) Triggers: particle burst (5 cyan sparks) Triggers: ui.update('mana') Sound: soft magical chime end note note right of Expired Fade out: opacity 1→0 over 300ms No sound Remove from entity list end note ``` ### Collectible: Iron Shard ```mermaid stateDiagram-v2 [*] --> Spawning: enemy death Spawning --> Active: spawn animation (250ms) with metallic flash Active --> Collected: player clicks within 22px Active --> Expired: lifetime 10s exceeded Active --> Attracting: magnetism unlocked, within 120px Collected --> [*]: add Iron Shards + floating "+X" Expired --> [*]: fade out (400ms) Attracting --> Collected: reaches player position Attracting --> Expired: lifetime exceeded note right of Spawning Sprite: spark (gray, scale 1.5) Position: at enemy death location Animation: scale 0→1 (250ms) Spawn: with metallic flash effect Value: shows 5/15/20 on hover Sprite: spark (gray, scale 1.5 for small, 2.0 for large) end note note right of Active Visual: gray crystal bob, metallic sheen Clickable radius: 22px Shows value on hover Drifts slowly downward (8px/sec) Magnetism: when active, floats toward player at 180px/sec end note note right of Collected Triggers: currency.add('ironShards', value) Triggers: floatingText("+{value}⚙️", silver) Triggers: particle burst (7 gray crystals) Triggers: ui.update('ironShards') Sound: metallic clink end note ``` ### Collectible: Crystal Essence ```mermaid stateDiagram-v2 [*] --> Spawning: golem/champion death (rare) Spawning --> Active: spawn animation (400ms) with purple flash Active --> Collected: player clicks within 25px (generous) Active --> Expired: lifetime 15s exceeded Active --> Attracting: magnetism always active, within 150px Collected --> [*]: add Crystal Essence + celebration Expired --> [*]: fade out (500ms) with sad sound Attracting --> Collected: reaches player position Attracting --> Expired: lifetime exceeded note right of Spawning Sprite: spark (purple, scale 2.0) Position: at enemy death location Animation: scale 0→1 (400ms) Spawn: with dramatic burst effect (15 particles) Has glow: true NEVER auto-despawns if on screen end note note right of Active Visual: purple glow, pulsing aura Clickable radius: 25px (generous) Shows "💎" on hover Bob amplitude: 3px Bob speed: 1 Hz Magnetism: always active, floats toward player at 250px/sec end note note right of Collected Triggers: currency.add('crystalEssence', value) Triggers: floatingText("+{value}💎", purple, large) Triggers: screen flash (purple tint) Triggers: particle burst (15 purple crystals) Triggers: ui.celebrate() Triggers: ui.update('crystalEssence') Sound: magical chime + echo end note note right of Expired Fade out: opacity 1→0 over 500ms Sound: sad magical tone Remove from entity list end note ``` ### Collectible: Element Sprite (Charge) ```mermaid stateDiagram-v2 [*] --> Spawning: periodic timer (every 8-12s) Spawning --> Active: fade in (300ms) at random orbit position Active --> Collected: player clicks within 18px or hovers Active --> Expired: lifetime 6s exceeded Collected --> [*]: add Charge + Mana + floating "+2⚡" Expired --> [*]: fade out (200ms) note right of Spawning Sprite: spark (element-colored, scale 1.0) Position: random orbit around rune circle Element colors: Fire (#ff6b354), Ice (#00ffff), Arcane (#bf5eff), Void (#1a1a2e) Animation: fade in 300ms Spawn: when wave 3+ complete end note note right of Active Visual: colored spark, matches element Clickable radius: 18px Shows "+2⚡ + 1💧" on hover (Charge + Mana) Orbits near rune circle Orbit speed: 60px orbit at radius 60px Orbit duration: 8-12s before despawn end note note right of Collected Triggers: currency.add('elementalCharge', 2) Triggers: currency.add('mana', 1) Triggers: floatingText("+2⚡ +1💧", element color) Triggers: particle burst (3 colored sparks) Triggers: ui.update('elementalCharge') Triggers: ui.update('mana') Sound: elemental fizz end note note right of Expired Fade out: opacity 1→0 over 200ms No sound Remove from entity list end note ``` ## CONFIG Spec: entities Section ```javascript // Entity Configuration for Spellforge Arena // Each entity type has visual specs, state definitions, and behaviors CONFIG.entities = { // Player Spell Projectiles spellProjectile: { sprite: 'fireball', scale: 1.5, team: 'player', states: { spawning: { type: 'scaleIn', duration: 100, invulnerable: true, }, flying: { type: 'animate', frames: [0, 1, 2], frameDuration: 50, flipX: false, rotation: true, }, impact: { type: 'burst', duration: 200, particles: 'spark', particleCount: 5, particleColor: 'elementBased', }, }, speed: 300, // pixels per second lifetime: 2, // seconds pierceCount: 1, trail: { enabled: true, sprite: 'spark', interval: 100, // ms between particles color: 'elementBased', lifetime: 500, }, glow: { enabled: true, color: 'elementBased', strength: 0.3, pulse: true, }, }, // Enemies wisp: { sprite: 'ghost', scale: 1.2, team: 'enemy', hp: 10, damage: 0, // No attack damage speed: 80, // pixels per second (fast) states: { spawning: { type: 'fadeIn', duration: 200, invulnerable: true, }, moving: { type: 'animate', frames: [0, 1, 2, 3], frameDuration: 200, flipX: true, // Flip based on horizontal direction }, dying: { type: 'fadeOut', duration: 300, particles: 'spark', particleCount: 5, particleColor: '#00ffff', spawnCollectible: { type: 'manaFragment', value: 3, chance: 1.0, // 100% drop }, }, }, reward: { mana: 3, chance: 1.0, }, healthBar: { show: true, width: 30, height: 3, yOffset: -8, color: '#00ffff', }, }, guardian: { sprite: 'knight', scale: 2.0, team: 'enemy', hp: 30, damage: 15, speed: 50, // pixels per second (medium) states: { spawning: { type: 'scaleIn', duration: 250, invulnerable: true, }, moving: { type: 'animate', frames: [0, 1, 2, 3], frameDuration: 200, flipX: true, }, fighting: { type: 'animate', frames: [2, 3], frameDuration: 100, spawnProjectile: true, }, dying: { type: 'fadeOut', duration: 400, particles: 'spark', particleCount: 7, particleColor: '#c0c0e0', spawnCollectible: { type: 'ironShard', value: 5, chance: 1.0, }, }, }, reward: { mana: 2, chance: 1.0, ironShards: 5, chance: 1.0, }, healthBar: { show: true, width: 40, height: 4, yOffset: -6, color: '#4caf50', }, weakness: { fire: 0.2 }, // +20% damage from fire resistance: { ice: 0.2 }, // -20% damage from ice }, golem: { sprite: 'slime', scale: 2.0, team: 'enemy', hp: 150, damage: 25, speed: 20, // pixels per second (very slow) isBoss: true, states: { teased: { type: 'static', duration: 3000, animation: 'bob', }, spawning: { type: 'scaleIn', duration: 500, invulnerable: true, }, moving: { type: 'animate', frames: [0, 1], frameDuration: 400, flipX: false, }, dying: { type: 'fadeOut', duration: 800, particles: 'spark', particleCount: 30, particleColor: '#a0a0a0', screenShake: { enabled: true, intensity: 5, duration: 100, }, spawnCollectible: { type: 'ironShard', value: 15, chance: 1.0, }, spawnCollectible: { type: 'crystalEssence', value: 1, chance: 0.3, }, }, }, reward: { mana: 5, chance: 1.0, ironShards: 15, chance: 1.0, }, healthBar: { show: true, width: 60, height: 6, yOffset: -10, color: '#ff6b354', }, weakness: { void: 1.0 }, // Void does full damage resistance: { fire: 0.5, ice: 0.5 }, // 50% reduction from fire/ice }, champion: { sprite: 'wizard', scale: 1.2, team: 'enemy', hp: 80, damage: 20, speed: 60, // pixels per second (medium-fast) isElite: true, states: { teased: { type: 'static', duration: 5000, uiIndicator: '⚠️ CHAMPION APPROACHING', }, spawning: { type: 'fadeIn', duration: 400, invulnerable: true, }, moving: { type: 'animate', frames: [0, 1, 2, 3], frameDuration: 150, flipX: true, }, casting: { type: 'animate', frames: [2, 3], frameDuration: 250, }, dying: { type: 'fadeOut', duration: 600, particles: 'spark', particleCount: 15, particleColor: '#bf5eff', spawnCollectible: { type: 'ironShard', value: 20, chance: 1.0, }, spawnCollectible: { type: 'crystalEssence', value: 3, chance: 0.6, }, }, }, reward: { mana: 5, chance: 1.0, ironShards: 20, chance: 1.0, }, healthBar: { show: true, width: 50, height: 5, yOffset: -8, color: '#9932cc', }, abilities: { summonWisps: { cooldown: 5000, count: 2, }, counterspell: { cooldown: 2000, damage: 10, }, }, weakness: 'rotating', // Changes each wave }, // Collectibles manaFragment: { sprite: 'spark', scale: 1.2, color: '#00ffff', lifetime: 8, collectRadius: 20, magnetRadius: 100, magnetStrength: 200, bobAmplitude: 2, bobSpeed: 2, value: 3, spawnAnimation: 'popIn', spawnAnimationDuration: 200, collectAnimation: 'burst', particleCount: 5, particleColor: '#00ffff', showsValue: true, sound: 'mana_collect', }, ironShard: { sprite: 'spark', scale: 1.5, color: '#808080', lifetime: 10, collectRadius: 22, magnetRadius: 120, magnetStrength: 180, bobAmplitude: 2, bobSpeed: 1.5, value: 5, spawnAnimation: 'popIn', spawnAnimationDuration: 250, collectAnimation: 'burst', particleCount: 7, particleColor: '#c0c0e0', metallic: true, showsValue: true, sound: 'iron_collect', }, crystalEssence: { sprite: 'spark', scale: 2.0, color: '#9932cc', lifetime: 15, collectRadius: 25, magnetRadius: 150, magnetStrength: 250, bobAmplitude: 3, bobSpeed: 1, value: 1, spawnAnimation: 'popIn', spawnAnimationDuration: 400, collectAnimation: 'burst', particleCount: 15, particleColor: '#b34dff', glow: true, showsValue: true, sound: 'essence_collect', neverDespawnOnScreen: true, celebrate: true, }, elementSprite: { sprite: 'spark', scale: 1.0, color: 'varies', // Set by element type lifetime: 6, collectRadius: 18, magnetRadius: 80, magnetStrength: 150, bobAmplitude: 2, bobSpeed: 2.5, value: 2, // Charge value orbitRadius: 60, orbitSpeed: 1, spawnAnimation: 'fadeIn', spawnAnimationDuration: 300, collectAnimation: 'burst', particleCount: 3, particleColor: 'varies', showsValue: true, sound: 'element_collect', orbit: true, }, }; ```