Go to file
Brian Fertig db258bdcae Added Read Me 2026-04-12 08:47:21 -06:00
.claude Campaign 4 2026-03-21 15:07:09 -06:00
assets feat: implement smite skill, rework enfeeble to hive_link/wound, update card skills and flavor texts 2026-04-04 09:26:01 -06:00
data balance: increase skill values and stats across multiple cards 2026-04-04 10:43:52 -06:00
src feat(skirmish): unlock all levels for testing by removing level restriction logic 2026-04-04 13:20:06 -06:00
CLAUDE.md refactor(ui): upgrade to 1920x1080 resolution with responsive scaling 2026-03-12 23:52:11 -06:00
README.md Added Read Me 2026-04-12 08:47:21 -06:00
index.html feat(ui): add custom fonts and apply Audiowide/RaiderCrusader across all scenes 2026-03-15 13:57:59 -06:00
start_web.sh initial commit 2026-03-12 16:36:32 -06:00

README.md

Tyrants Edge

A browser-based deck-building card game built with Phaser 3. Command five factions across a tactical battlefield — deploy assault cards, trigger skill chains, and defeat your opponent's commander in turn-based 1v1 combat.

Quick Start

Requirements: Python 3, a modern browser (Chrome/Firefox/Safari)

./start_web.sh
# or
python3 -m http.server 8000

Open http://localhost:8000. No build step — the game runs directly from source as ES modules. Refresh the page after any code change.

Game Modes

Mode Description
Campaign Five faction story campaigns, each with ~7 missions and lore. Defeat enemy commanders to unlock new campaigns and earn card rewards.
Skirmish Standalone battles. Choose a card level (15) and difficulty (Easy / Medium / Hard / Legendary), then either pick a premade deck or draft one from a budget card pool.
Deck Builder Construct custom decks: 1 commander + 310 assault cards, max 3 copies of any card.
Collection Browse and filter your owned cards by faction and rarity.
Store Spend gold on faction-specific booster packs (5 factions, 4 cards per pack).
Fusion Sacrifice 3 cards of the same rarity to forge 1 card of the next rarity (common → rare → epic → legendary).

Architecture

Vanilla JavaScript with Phaser 3 (v3.90.0, loaded via CDN). No bundler, no npm, no build step.

Scene Flow

BootScene → IntroScene → MainMenuScene
                              │
              ┌───────────────┼───────────────────┐
              ▼               ▼                   ▼
    CampaignSelectScene  SkirmishSetupScene  DeckBuilderScene
              │               │
    CampaignScene    SkirmishDeckSelectScene
              │               │
              └───────────────┘
                      ▼
                 BattleScene
                      │
               BattleResultScene

Other scenes: CollectionScene, StoreScene, FusionScene

BootScene preloads all JSON data and card art, then initialises global managers before handing off to the intro video.

Global Managers

Stored in Phaser's game registry; access anywhere with this.registry.get(key).

Key Class Purpose
cardManager CardManager Card definitions and instance creation
packManager PackManager Booster pack opening and drop-rate logic
save SaveManager Versioned localStorage persistence
deckManager DeckManager Deck validation and construction
tutorial TutorialManager Tutorial stage progression tracking
missions raw JSON Campaign mission data

Source Layout

src/
├── game.js                 # Phaser config & scene list
├── combat/
│   ├── CombatEngine.js     # Turn loop and phase resolution
│   ├── SkillProcessor.js   # Skill effect evaluation
│   └── CombatAI.js         # AI card selection
├── managers/
│   ├── CardManager.js
│   ├── PackManager.js
│   ├── SaveManager.js
│   ├── DeckManager.js
│   └── TutorialManager.js
├── objects/
│   ├── CardObject.js       # Card rendering (Phaser Container)
│   ├── BattleField.js      # Lane layout and positioning
│   ├── CardTooltip.js      # Hover tooltip
│   └── HealthBar.js        # Health/armor bar
├── scenes/                 # One file per scene (14 total)
└── utils/
    └── RNG.js              # Seeded deterministic random

Combat System

Turn Phases

Each turn runs the following phases in order:

  1. Draw — both sides draw up to a hand limit (MAX_HAND = 3)
  2. Deploy — cards are placed into open lanes (MAX_LANES = 4)
  3. Activationon_turn_start skill triggers fire
  4. Rupture — wound/DoT stacks deal damage
  5. Jam — jammed cards are skipped this turn
  6. Commander Skills — commander passive/active skills resolve
  7. Attack — each lane attacks the opposing lane; skills fire on pre-attack/on-attack/on-kill triggers
  8. Cleanup — dead cards are removed, state is prepared for next turn

CombatEngine.js maintains an event queue so the UI can animate each step sequentially without the logic blocking.

Skills

SkillProcessor.js resolves all skill effects. Skills are attached to cards with an optional value, trigger, and all flag.

Skill Reference

Category Skills
Offense strike, swipe, pierce, wound, mortar, flurry, berserk
Control jam, enfeeble, weaken
Defense protect, counter, wall, armored, carapace
Support heal, rally, siphon, drain, cleanse, sanctify
Special burrow, molt, hive_link, evolve, legion, valor, tribute

Triggers

Trigger When it fires
preBattle Once, at the start of the match
on_turn_start At the beginning of each turn
preAttack Before this card attacks
on_attack When this card attacks
on_defend When this card is attacked
on_kill When this card destroys an enemy
passive Continuous effect

Win Conditions

  • Commander Kill — reduce the opponent's commander health to zero
  • Overwhelm — triggered when certain conditions are met (see overwhelm visual effect in BattleScene)

Deterministic RNG

RNG.js provides a seeded pseudo-random number generator. Passing the same seed to CombatEngine and CombatAI produces an identical, replayable battle.

Data Model

All game content lives in data/ as JSON. No server needed — BootScene fetches these files directly.

cards.json

104 cards across 5 factions. Each card supports multiple level tiers with independent stats and skills.

{
  "id": "imp_cmd_1",
  "name": "Warlord Voss",
  "faction": "imperial",
  "type": "commander",
  "rarity": "legendary",
  "levels": [
    {
      "attack": 0,
      "health": 30,
      "armor": 2,
      "delay": 0,
      "skills": [
        { "name": "strike", "value": 4, "trigger": "on_attack" }
      ]
    }
  ]
}

Factions: imperial, raider, bloodthirsty, xeno, righteous
Types: commander, assault
Rarities: common, rare, epic, legendary

missions.json

37 missions across all campaigns.

{
  "id": "mission_001",
  "name": "First Contact",
  "chapter": 1,
  "campaignId": "campaign_raider",
  "enemyLevel": 1,
  "opponent": {
    "commander": "raider_cmd_1",
    "cards": ["card_id", "..."]
  },
  "rewards": { "gold": 100, "cards": ["card_id"] }
}

campaigns.json

5 faction campaigns. Each references an ordered list of mission IDs and a starter card reward.

packs.json

5 faction packs at 400 gold each. Each pack has 4 card slots — 3 guaranteed commons and 1 weighted slot (35% common / 50% rare / 10% epic / 5% legendary).

skills.json

Skill reference data (name, description, trigger, category). Skills are also defined inline on cards in cards.json.

skirmish_decks.json

Predefined decks used in skirmish mode, annotated with difficulty and faction summary.

Save Data

Stored in localStorage under the key tyrants-edge-save. The current schema is version 3; SaveManager handles forward migration automatically.

{
  "version": 3,
  "gold": 300,
  "level": 1,
  "collection": { "card_id": 2 },
  "decks": [
    {
      "id": "deck_1",
      "name": "My Deck",
      "commander": "imp_cmd_1",
      "cards": ["card_id", "card_id", "..."]
    }
  ],
  "campaignProgress": {
    "completedMissions": ["mission_001"],
    "currentCampaign": "campaign_raider"
  },
  "unlockedCampaigns": ["campaign_raider"],
  "tutorialProgress": { "completedStages": [1, 2] },
  "starterDeckReceived": false
}

To reset save state, run in the browser console:

localStorage.removeItem('tyrants-edge-save');

Assets

assets/
├── fonts/          # RaiderCrusader (headers), Audiowide (body)
├── video/          # intro.mp4, menu_bg.mp4, campaign/mission backgrounds, forge video
├── audio/          # 6 battle music tracks, skill/action SFX, UI sounds
└── images/
    ├── cards/      # Card art (one image per card)
    ├── packs/      # Booster pack artwork
    └── ui/         # vs icon, attack indicator, battle backgrounds, spritesheets

Development Notes

  • No build step. Edit any .js file and refresh the browser — ES modules are loaded directly.
  • No linting or test suite is configured.
  • Phaser version is pinned in index.html via CDN. Upgrade by changing the script URL.
  • Adding a card: add an entry to data/cards.json and place the card art in assets/images/cards/. The card ID is used as the image key in BootScene.
  • Adding a skill: implement the effect in SkillProcessor.js and add the reference entry to data/skills.json.
  • Adding a scene: create the file in src/scenes/, then register it in src/game.js.
  • Animation timing: stat changes must never appear before their animations. Use snapshot-before / refreshStatsOnly / restore-reapply patterns — see feedback_animation_timing.md in project memory.