Skip to content

feat(retention): next-goal on the run-end screen, and a codex that pa… - #26

Merged
FiddlyDigital merged 1 commit into
mainfrom
next-goal-codex
Aug 1, 2026
Merged

feat(retention): next-goal on the run-end screen, and a codex that pa…#26
FiddlyDigital merged 1 commit into
mainfrom
next-goal-codex

Conversation

@FiddlyDigital

Copy link
Copy Markdown
Owner

…ys out

Two retention features that both attack the same problem — the game recorded progress but never gave the player something to aim at.

Next goal (src/views/nextGoal.ts)

A run ending is the moment a player decides whether to hit Restart, and the screen was a dead end: stats, then nothing. It now names the single nearest unfinished thing:

"One floor short of your deepest (9). One."
"2 codex entries from complete — 21/23 found."
"You found 2 of 3 smiths — the Spear of Lugh needs 1 more."

Ordered by how close a goal is, not how big — a record two floors away pulls harder than "collect everything". Pure and host-free: the caller supplies the cross-run records, which live outside the simulation. Victory reframes around the codex and the heat ladder instead.

The records have to be read BEFORE recordRunEnd, which folds this run into them — otherwise the line would compare the run against itself. Added StorageService.getDeepestFloor for that.

Codex completion + unlocks (src/codex.ts)

The codex was a read-only trophy case. It now shows a completion bar (9 / 23 discovered) and an unlock ladder: 25/50/75/100% each grant a small permanent perk at every future run start — 50 starting gold, a tier-I Geis, a Deathward charge, a tier-II Geis. Configured in balance.json's codex.unlocks (+ schema), applied via Game.applyCodexUnlocks(pct).

The host computes the percentage from storage and passes it in, so the simulation still touches no persistence. Boon rolls go through the run's rng, so a seeded run's unlocks are reproducible too.

Discovery counting ignores ids that no longer match live content — after the Tuatha Dé rename, a returning player's saved 'scathach'/'fedelm'/'bricriu' entries would otherwise have inflated their total.

  • balance.json + schema + balance.ts: codex.unlocks ladder
  • runSetup.ts: applyCodexUnlocks; game.ts delegator; main.ts wiring
  • codex-modal + style.css: progress bar and ladder (earned vs locked)
  • game-over-modal/ui.ts/main.ts: the next-goal line
  • 27 new tests (13 goal-selection, 14 codex/unlock), both new modules added to the coverage include list
  • README: two Core-systems rows, file-tree entries

Verified live: the ladder renders at a seeded 39% with the first rung earned and the rest locked, no page errors.

Claude-Session: https://claude.ai/code/session_01V6kP5vUAcNbxLK5EnPKAhv

…ys out

Two retention features that both attack the same problem — the game recorded
progress but never gave the player something to aim at.

## Next goal (src/views/nextGoal.ts)

A run ending is the moment a player decides whether to hit Restart, and the
screen was a dead end: stats, then nothing. It now names the single nearest
unfinished thing:

  "One floor short of your deepest (9). One."
  "2 codex entries from complete — 21/23 found."
  "You found 2 of 3 smiths — the Spear of Lugh needs 1 more."

Ordered by how *close* a goal is, not how big — a record two floors away
pulls harder than "collect everything". Pure and host-free: the caller
supplies the cross-run records, which live outside the simulation. Victory
reframes around the codex and the heat ladder instead.

The records have to be read BEFORE recordRunEnd, which folds this run into
them — otherwise the line would compare the run against itself. Added
StorageService.getDeepestFloor for that.

## Codex completion + unlocks (src/codex.ts)

The codex was a read-only trophy case. It now shows a completion bar
(`9 / 23 discovered`) and an unlock ladder: 25/50/75/100% each grant a small
permanent perk at every future run start — 50 starting gold, a tier-I Geis,
a Deathward charge, a tier-II Geis. Configured in balance.json's
`codex.unlocks` (+ schema), applied via Game.applyCodexUnlocks(pct).

The host computes the percentage from storage and passes it in, so the
simulation still touches no persistence. Boon rolls go through the run's rng,
so a seeded run's unlocks are reproducible too.

Discovery counting ignores ids that no longer match live content — after the
Tuatha Dé rename, a returning player's saved 'scathach'/'fedelm'/'bricriu'
entries would otherwise have inflated their total.

- balance.json + schema + balance.ts: codex.unlocks ladder
- runSetup.ts: applyCodexUnlocks; game.ts delegator; main.ts wiring
- codex-modal + style.css: progress bar and ladder (earned vs locked)
- game-over-modal/ui.ts/main.ts: the next-goal line
- 27 new tests (13 goal-selection, 14 codex/unlock), both new modules added
  to the coverage include list
- README: two Core-systems rows, file-tree entries

Verified live: the ladder renders at a seeded 39% with the first rung earned
and the rest locked, no page errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V6kP5vUAcNbxLK5EnPKAhv
@FiddlyDigital
FiddlyDigital merged commit 12995af into main Aug 1, 2026
1 check passed
@FiddlyDigital
FiddlyDigital deleted the next-goal-codex branch August 1, 2026 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants