Skip to content

EchoSpire — Mini-Games Design Reference

Status: Current — verified 2026-08-27. All five faction mini-game handlers exist in src/EchoSpire.API/Services/MiniGames/ (948 lines total) and the ✅ marks below are accurate. todo-inventory.md claimed four of these were unbuilt; that item was wrong and has been corrected. Owner: delan

Last updated: April 12, 2026


Overview

Each faction has one mini-game node woven into its tutorial rift. Mini-games are server-owned — the API holds all state, evaluates every move, and never exposes the solution to the client. The UX layer receives a MiniGameStateDto after each action and renders only what the server sends.

API contract (unchanged for all games)

POST   /api/v1/runs/{runId}/minigame/start    → MiniGameStateDto   (initial board)
GET    /api/v1/runs/{runId}/minigame           → MiniGameStateDto   (current board)
POST   /api/v1/runs/{runId}/minigame/action    → MiniGameStateDto   (after each move)
POST   /api/v1/runs/{runId}/minigame/resolve   → MiniGameResultDto  (final outcome + effects)

Implementation pattern

Each game lives in its own IMiniGameHandler class under src/EchoSpire.API/Services/MiniGames/. No controller or service changes are required to add a new game — just create the handler and register it with DI.


Game 1 — Stasis Field Calibration

Faction: The Valerii · Type string: StasisCalibration · Status: ✅ Implemented

Thematic basis

Valerius attempted a Stasis Lock — magnetising the Spire's core to freeze reality in perfect safety. The player is recalibrating a damaged field of stasis pylons before the breach consumes the outpost.

Rules

Property Value
Slots 3 pylons — PYLON_A, PYLON_B, PYLON_C
Turns 5
Mechanic Ordered sequence — activate all 3 pylons in the correct order
Correct order Seed-derived shuffle (deterministic per run + node index)
Correct step Slot enters Confirmed state; advance to next position
Wrong step Attempt resets to position 0; costs 1 turn
Win condition All 3 pylons confirmed before turns expire
Lose condition Turns reach 0 with sequence incomplete

Rewards

  • Success: block_bonus:+10 — gain 10 Block at the start of the next combat
  • Failure: damage:5 — take 5 damage immediately on resolution

Hint shown to player

"Observe the resonance pattern — each pylon pulses once in sequence at the start of the encounter."


Game 2 — Logic Cascade

Faction: The Axiom · Type string: SyntactaLogicCascade · Status: ✅ Implemented

Thematic basis

Hesper attempted a Deep Sync — forcing a direct neural link to "solve" the universe. The player is completing a corrupted logic thread that the Axiom's Void-tech has partially recovered. Most of the pattern is clear; the final steps must be deduced.

Rules

Property Value
Slots 4 Logic Nodes — ALPHA, BETA, GAMMA, DELTA
Turns 4
Mechanic Pattern completion — the server reveals the first 2 elements of a 4-step sequence and the rule type; the player must deduce and input the remaining 2
Rule types (seed-derived, one of 3) Ascending cycle — ALPHA→BETA→GAMMA→DELTA (wraps); Descending cycle — DELTA→GAMMA→BETA→ALPHA (wraps); Mirror — sequence[0], sequence[3], sequence[1], sequence[2]
Revealed prefix First 2 elements shown in FlavorText as "Established pattern: ALPHA, GAMMA"
Rule name Shown in Hint so the player knows which rule applies
Correct step Advance to next position (positions 3 and 4)
Wrong step Reset attempt to position 2 (re-entering from where the known prefix ends); costs 1 turn
Win condition All 4 nodes confirmed before turns expire
Lose condition Turns reach 0

Rewards

  • Success: draw_bonus:+2 — draw 2 extra cards at the start of the next combat
  • Failure: hand_discard:2 — discard 2 random cards from the opening hand of the next combat

Flavor text template

"Established pattern: {node_0}, {node_1}. Rule: {rule_name}. Complete the sequence."


Game 3 — Echo Shard Distillation

Faction: The Syndicate · Type string: AethariDistillation · Status: ✅ Implemented

Thematic basis

Vex attempted Alchemical Distillation — forcing the Spire to attract multiple high-yield realities simultaneously. The player is harvesting two primed energy veins from a volatile dimensional field before the unstable veins discharge and the window closes.

Rules

Property Value
Slots 4 Echo Veins — VEIN_PRIME, VEIN_ECHO, VEIN_FLUX, VEIN_RESONANCE
Turns 4
Mechanic Set selection (no required order) — 2 of the 4 veins are "primed"; identify and harvest both
Primed veins 2 slots chosen by seed-derived selection
Primed tap Slot state → Confirmed; turn is NOT consumed
Empty tap Slot state → Locked (cannot be tapped again); costs 1 turn
Win condition Both primed veins confirmed
Lose condition Turns reach 0, or both remaining un-confirmed slots are Locked

Key difference from StasisCalibration: order is irrelevant; wrong taps lock the slot permanently rather than resetting the attempt.

Rewards

  • Success: damage_pct:+15 — all damage increased by 15% for the rest of the run (Echo-Shard augmentation)
  • Failure: hp_loss:8 — lose 8 HP immediately on resolution

Hint shown to player

"Two veins pulse with dimensional energy. The others are cold. A wrong channel burns the circuit permanently."

Server-side CorrectSequence semantics

For this game, CorrectSequence holds the two primed slot IDs (unordered). The handler checks set membership rather than positional ordering.


Game 4 — Soul-Data Recovery

Faction: The Censors · Type string: AnnalisSoulDataRecovery · Status: ✅ Implemented

Thematic basis

Cavan attempted Temporal Extraction — pulling living data from past and future to create an eternal archive. The player is recovering three authentic Soul-Data fragments from a field of five before temporal drift corrupts the genuine records beyond recovery.

Rules

Property Value
Slots 5 Archive Fragments — FRAG_I, FRAG_II, FRAG_III, FRAG_IV, FRAG_V
Turns 7
Mechanic Timed set selection with drift — 3 of 5 fragments are authentic; identify and seal all 3
Authentic fragments 3 slots chosen by seed-derived selection
Authentic seal Slot state → Confirmed; does NOT cost a turn
False seal Slot state → Locked; costs 1 turn
Drift (per turn) At the start of turns 3, 5, and 7, one un-sealed authentic fragment randomly enters Locked state ("drifted beyond retrieval"); the player is notified via updated FlavorText
Win condition All 3 authentic fragments confirmed before 3 have drifted
Lose condition Turns reach 0, or so many authentic fragments have drifted that winning is mathematically impossible

Drift requires per-turn server logic. On each ApplyAction call, after processing the player's move, the handler checks if a drift event is due on the new turn number and applies it to the session state before returning the DTO.

Rewards

  • Success: echo_recall:1 — an Echo Recall card is permanently added to the deck (once per run)
  • Failure: deck_purge:1 — one card is permanently removed from the deck

Hint shown to player

"Three records are genuine. Two are fabrications from collapsed timelines. The archive is degrading — delay long enough and even the real ones will be lost."


Game 5 — Power Re-Route

Faction: The Salvari · Type string: SalvariPowerReroute · Status: ✅ Implemented

Thematic basis

Alden triggered the Emergency Decoupling — saving the universe through jury-rigged maintenance. The player is tracing a working power path through a damaged junction grid to restore systems before total blackout. Alden calls it a "heist"; it's actually keeping Sector 7 from going dark.

Rules

Property Value
Slots 6 junction nodes — SOURCE, BRANCH_A, BRANCH_B, JUNCTION, BYPASS, SINK
Turns 8
Mechanic Path tracing — there is exactly one valid 4-node path from SOURCE to SINK; find all intermediate nodes
Correct path A 4-node sequence (including SOURCE and SINK as fixed endpoints) derived from seed
Correct tap Slot state → Confirmed; does NOT cost a turn
Wrong tap Slot state → Locked ("crossed wire"); costs 1 turn
Win condition All 4 path nodes confirmed
Lose condition Turns reach 0

SOURCE and SINK are always the start and end of the path. The player need only identify the 2 intermediate nodes (BRANCH_A/B, JUNCTION, or BYPASS). The DTO should indicate SOURCE and SINK as special slots via their Hint field so the player knows they are fixed anchors.

Rewards

  • Success: energy_bonus:+1 — gain 1 extra Energy at the start of the next combat
  • Failure: hand_size:-1 — start the next combat with 1 fewer card in the opening hand

Hint shown to player

"SOURCE and SINK are anchored. The route between them runs through exactly two junctions. Cross a bad wire and it's locked — trace carefully."


Effects Reference

The Effects list in MiniGameResultDto uses a key:value string format. The run-state resolver maps these to concrete game mutations.

Effect string Meaning
block_bonus:+N Add N starting Block to the player's next combat
damage:N Deal N damage to the player immediately
draw_bonus:+N Draw N extra cards at the start of next combat
hand_discard:N Discard N random cards from the next combat's opening hand
damage_pct:+N Increase all player damage by N% for the rest of the run
hp_loss:N Remove N HP from the player immediately
echo_recall:1 Add an Echo Recall card permanently to the deck
deck_purge:1 Permanently remove one card from the deck
energy_bonus:+N Add N Energy at the start of the next combat
hand_size:-N Reduce opening hand size by N for the next combat

Adding a New Handler

  1. Create src/EchoSpire.API/Services/MiniGames/{Name}Handler.cs implementing IMiniGameHandler.
  2. Add the type to the MiniGameType enum in EchoSpire.Contracts/MiniGames/MiniGameDtos.cs.
  3. Register in Program.cs: csharp builder.Services.AddSingleton<IMiniGameHandler, YourNewHandler>();
  4. No changes required to MiniGameService, MiniGameController, or any DTO class.