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.mdclaimed 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
ApplyActioncall, 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
Hintfield 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¶
- Create
src/EchoSpire.API/Services/MiniGames/{Name}Handler.csimplementingIMiniGameHandler. - Add the type to the
MiniGameTypeenum inEchoSpire.Contracts/MiniGames/MiniGameDtos.cs. - Register in
Program.cs:csharp builder.Services.AddSingleton<IMiniGameHandler, YourNewHandler>(); - No changes required to
MiniGameService,MiniGameController, or any DTO class.