Commit Graph

27 Commits

Author SHA1 Message Date
Fredrik Johansson
3a741a7bfc Fix log entries appearing to lag one action behind
All checks were successful
Docker / build-and-push (push) Successful in 1m16s
Real bug, two parts:

1. renderLog appended the newest entry LAST in the DOM (so it could
   get its own element for the typewriter effect), but log.scrollTop
   = 0 scrolls to the TOP, where the older entries now sat. The
   newest line rendered below the fold, invisible until enough later
   entries pushed it into view — exactly "nothing appears until the
   next event." Fixed by putting the newest entry first.

2. Separately, the typewriter itself was applying to every log kind,
   including the player's own actions (upgrades, visits). Those took
   1-2s to fully print, so even after fixing the ordering, taking a
   second action while the first was still typing would silently
   snap the first to full text right as the second started — still
   reads as a one-action lag. Now only narrative kinds (event, kaos)
   animate; upgrades and visits confirm instantly. Also sped up the
   animation itself (4-8ms/char, was 8-18ms) so even narrative beats
   don't drag.

Also fixed Malmö universitet's map marker — it was placed near
Hyllie, nowhere near the actual campus at Universitetsholmen by the
harbor.

Verified via headless browser: a kaos event and a free location
visit both now appear at the top of the log immediately, not after
a subsequent action.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 22:14:06 +02:00
Fredrik Johansson
b610d27542 Replace Göran's portrait with a tighter, more intimate framing
All checks were successful
Docker / build-and-push (push) Successful in 1m17s
The original wide shot split focus between him and the full ritual
circle in the background, which is the game's set dressing more than
his — and put the dog on its own blanket further back, reading as
"a dog happens to be in this room" rather than his dog. New version
is a close single-candle framing: just him, the table, the mug, and
the dog curled at his feet. The warm, cozy light against rough
concrete does more comedic work too — he's the one person here who
hasn't noticed anything's wrong.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:54:24 +02:00
Fredrik Johansson
1aa9eb2ce8 Click a map marker to see its art at full size
Reuses the lightbox already built for the character gallery. Clicking
any location still triggers the visit as before, but now also probes
for that location's art and, if it exists, pops it up full-size with
a caption — no modal for locations that don't have art yet, the visit
still happens either way.

Also added a standing "about this place" blurb per location (map.ts's
new LOCATION_INFO), shown under the art. This is distinct from
LOCATION_VISITS' randomized per-visit outcome text in engine.ts, which
still changes every time — the blurb is a fixed description of the
place itself, not what just happened there.

Verified via headless browser: clicking Turning Torso's marker pops
the lightbox with its real art, label, and blurb, no console errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:42:28 +02:00
Fredrik Johansson
d2a8b71ffc Add all 9 location thumbnails
All map markers now show real art in their tooltip preview instead
of falling back to text-only. Fixed two filename mismatches against
what map.ts expects (id-based, e.g. "universitet.png" not the
Swedish definite form "universitetet.png"). Kept the stronger of two
Ribersborg takes — the one with Turning Torso on the skyline ties it
back to the game's central landmark, and the ducks facing camera
reads eerier than facing away.

Verified via headless browser: all 9 markers present, thumbnails
load without error, tooltip renders image + label together.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:27:54 +02:00
Fredrik Johansson
899ab72c80 Location thumbnails on the map, full-art archive mode, more content
- Map markers now show a tiny thumbnail preview in their tooltip when
  art exists for that location (same missing-asset-is-fine fallback
  as character portraits — onerror just removes the broken img).
- Two new locations, both free-roam from the start: Möllevångstorget
  and Malmö universitet (the latter ties into the researcher
  character's arc). VISITABLE_LOCATION_IDS picks them up automatically
  since it's derived from the data, not a separate list.
- Sällskapet gets a second mode: "Fullständigt arkiv" shows every
  character's real portrait and bio regardless of story progress
  (bypassing the usedEventIds lock), and clicking any known portrait
  opens a lightbox at full size instead of the cropped card thumbnail.
- All 9 character portraits are now in and wired (fixed two more
  filename mismatches along the way: anneli-karin and the rest use
  hyphens, not underscores, matching what was actually generated).
- More content: 2 new location-visit variants each for the two new
  areas, 6 new Standard events (including a found 1930s photograph
  that seems to show Lindqvist in a room nobody recognizes), 4 new
  Kaos events tied to the new locations and existing ones.
- Caught and fixed a bug in my own new content before commit: an
  event's requires.completedEventId pointed at an upgrade id, which
  can never appear in usedEventIds — switched to a minRitual check
  that actually gates on the right precondition.

Verified: 15/15 tests, clean typecheck and build, and a real
headless-browser pass — all 9 map markers present, full-archive mode
correctly bypassing locks, and the lightbox opening at full size with
a caption.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:09:43 +02:00
Fredrik Johansson
aeedf0abb5 Add offline progress, tab haunting, character gallery, more flavor
Real depth additions, not a reskin of another idle game:

- applyOfflineProgress: the cult continues while the tab is closed or
  backgrounded (rAF throttles hard when hidden, so real time drifts
  well past simulated time). Approximates tick()'s per-second rates
  over the elapsed window, capped at 24h, with a narrative "while you
  were away" log line scaled to how long that was. Can end the game
  in a win or loss if the numbers would have gotten there. Re-checked
  on every tab-visibility return too, not just page load.
- Tab-title haunting: document.title cycles short eerie lines
  ("Han väntar…", "Havet kallar…") while the tab is hidden, restores
  on return.
- New late-game upgrade "Viskningen leder er" — once bought, the cult
  visits map locations on its own occasionally without a click. A
  small loss-of-agency horror beat, not just a QoL toggle.
- Log's newest line now types itself out, with characters
  occasionally swapped for occult symbols (☿☠ψ) at a rate scaled to
  current dread. Older lines stay static and legible — this never
  applies retroactively.
- New "Sällskapet" character gallery: cards for every named recurring
  character, locked to a silhouette + "???" until you've actually met
  them (checked against usedEventIds). Portraits are optional — missing
  art falls back to an initial-letter placeholder, so this works
  incrementally as art gets added. First five real portraits included.
- Real bug fix: several Kaos events referenced characters (Göran,
  Bengt-Åke, the Sydsvenskan journalist) as if already introduced,
  but had no ordering dependency on the Standard event that actually
  introduces them — so a fresh cultist could show up in the log
  already "familiar" before you'd ever met them. Gated with
  requires.completedEventId.
- More flavor text throughout: two new variants per location visit,
  6 new Standard events, 4 new Kaos events.

Evaluated three other ideas from the same source and declined them:
a generic milestone-triggered log (Djupet's log already reacts to
real state, not arbitrary point totals), an investigator combat
minigame (hemlighet draining to zero already does this job, and
tower-defense clicking would fight the game's actual tone), and a
node-sequencing ritual minigame (real scope for a twitch mechanic
that doesn't match the rest of the game's pacing).

Verified: 15/15 tests passing, clean typecheck and production build,
and a real headless-browser pass — offline catch-up after a
simulated 5-hour gap, tab-title cycling and restore, and the
character gallery rendering real portraits alongside locked cards.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 20:53:26 +02:00
Fredrik Johansson
1eb9c43625 Add favicon
All checks were successful
Docker / build-and-push (push) Successful in 43s
Purple downward-chevron mark matching the site's eldritch-purple accent, in the same rounded-square favicon style used across the other self-hosted projects.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 19:49:28 +02:00
Fredrik Johansson
ee60a9f4d2 Add .dockerignore to shrink the build context sent to the daemon
All checks were successful
Docker / build-and-push (push) Successful in 51s
node_modules/.git/dist were being sent on every build with no
.dockerignore at all — same class of fix as goonk's recent deploy-speed
pass. Verified by building with the new file in place (adventure and
new spot-checked with a full container run + health check; the rest
share the same multi-stage Dockerfile pattern).
2026-07-16 18:48:35 +02:00
Fredrik Johansson
bde809e862 Extend the endgame, add more content, make kaos events recur
All checks were successful
Docker / build-and-push (push) Successful in 43s
Balance: an optimal-play simulation showed the game finishing in
under 3 minutes, mostly because torso_beacon + grand_ritual_prep
alone pushed ritualRate to 2.5 — enough to clear the last 50 ritual
points in 20 seconds. Softened those boosts (0.5→0.15, 2→0.35),
raised deepen_ritual's cost curve so it's a real endgame sink instead
of a one-off top-up, and added two new late-game upgrades (sunken
choir, nine filled chairs) between grand_ritual_prep and the win.
Re-simulated: a greedy optimal-play bot now takes ~5 minutes instead
of ~3 and surfaces ~40 distinct events instead of ~30 out of a much
larger pool — real (non-bot) play should run considerably longer.

Content: added 8 new high-dread late-game standard events (gated up
to minDread 400, since nothing previously escalated past 75) and 7
new kaos events, plus one more choice event.

Kaos events no longer get marked as permanently used — they're
chaos-relief flavor, not narrative progression, and a ~24-entry pool
(now 30) was depleting for good over a long game. Standard/chain
events remain single-use.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 19:29:04 +02:00
Fredrik Johansson
323a61997f Lighten win/loss overlay scrim to match the intro screen's touch
All checks were successful
Docker / build-and-push (push) Successful in 43s
The overlay's radial gradient was much darker/broader than the intro
scrim, crushing the win/loss artwork (the inverted Torso, the ritual
circle) that the intro screen showed off fine. Dropped the opacity
stops so the same restrained look applies everywhere.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 16:54:03 +02:00
Fredrik Johansson
b7c052a11f Fix silently-dropped log entries past the 40-line cap, add pause, clarify locations panel
All checks were successful
Docker / build-and-push (push) Successful in 42s
- The log view only re-rendered when state.log.length changed, but the
  log is capped at 40 entries — so once a run had logged 40+ things
  (easy in a normal session), every entry after that point, including
  choice-event outcomes, upgrade purchases, and location visits,
  stopped appearing even though the underlying state updated. Fixed
  by tracking a monotonic logSeq counter that increments on every
  push regardless of the cap, and rendering off that instead of
  array length. Consolidated the repeated unshift+cap logic into one
  pushLog() helper so future call sites can't reintroduce the bug.
- Added a pause button (and "PAUSAD" indicator) that freezes the tick
  loop without touching game state, so a hectic run can be paused to
  think without it counting as a save-scummy state mutation. Manual
  actions (buying upgrades, visiting locations) still work while
  paused, since that's usually the point of pausing.
- The "Aktiva områden" sidebar only ever listed the 3 story-gated
  core areas, while the map has 7 clickable locations — making it
  look like 4 of the map pins didn't really exist. Split the panel
  into "Ritualens kärnplatser" (the 3 gated ones, unlock status shown
  as before) and "Övriga platser" (the 4 always-open flavor
  locations), so the sidebar and map agree.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 16:49:37 +02:00
Fredrik Johansson
4b4e5c14aa Merge origin/main
All checks were successful
Docker / build-and-push (push) Successful in 42s
2026-07-13 13:30:30 +02:00
Fredrik Johansson
efc19bac1d Bump version to 0.4.0, update changelog, fix Swedish typos
Covers the choice events, NPC chains, location text variety, ambient
visual reactivity, intro screen, win/loss art, and the abandon option
added across the last few changes. Also fixes a handful of spelling
and word-choice mistakes found in a sweep of the event text
("blinkmat"→"blinkat", a "summera"/summon false-friend, a stray
English "return" in "Returndatumet", and one word that didn't fit).

Intro and win/loss screens now use a constrained gradient scrim
around the text instead of a flat overlay covering the whole image,
so the artwork stays visible instead of being crushed to black.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 13:21:23 +02:00
Fredrik Johansson
d039dfb019 Bump version to 0.4.0, update changelog, fix Swedish typos
All checks were successful
Docker / build-and-push (push) Successful in 42s
Covers the choice events, NPC chains, location text variety, ambient
visual reactivity, intro screen, win/loss art, and the abandon option
added across the last few changes. Also fixes a handful of spelling
and word-choice mistakes found in a sweep of the event text
("blinkmat"→"blinkat", a "summera"/summon false-friend, a stray
English "return" in "Returndatumet", and one word that didn't fit).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 10:10:40 +02:00
Fredrik Johansson
4d47409e03 Add intro screen, win/loss art, and a way to abandon the ritual
- Adds a full-screen intro/title screen (new 'intro' game phase) with
  a moody Malmö/Turning Torso background and a "Börja ritualen"
  button; the game no longer starts ticking until the player begins.
- Win and loss overlays now show matching generated artwork behind
  the existing text, instead of a flat scrim.
- New "Avbryt" header button lets the player abandon a run mid-game
  (with a confirm prompt) via a new 'abandoned' phase, reusing the
  existing overlay/restart flow.
- Source images converted from PNG (~2.1MB each) to WebP (~120KB
  each) and placed under public/img/ so Vite serves them as-is.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 09:54:46 +02:00
Fredrik Johansson
10c7999701 Merge feature/interactive-events: choice events, NPC chains, visual reactivity, location variety
All checks were successful
Docker / build-and-push (push) Successful in 42s
2026-07-13 00:02:58 +02:00
Fredrik Johansson
6ed9d2dac3 Add ambient visual reactivity and location visit variety
- #app's filter (hue-rotate/saturate) now tracks dread continuously,
  and a fixed vignette bleeds red as hemlighet drops below 40 — no
  new assets, just CSS driven by existing state.
- A kaos log entry now triggers a brief screen-glitch shake.
- Location visits pick from 3 flavor-text variants per site instead
  of a single fixed line, so repeat visits don't repeat verbatim.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 00:01:51 +02:00
Fredrik Johansson
80fdebf102 Add flag-gated NPC event chains for Broder Lindqvist and Syster Hassan
Events can now depend on a previously-set flag and a completed event
id, letting a choice made early in the game (e.g. whether Lindqvist's
whisper was heeded) shape which follow-up events surface later. Adds
two 3-step chains as a first example of persistent NPC arcs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 23:53:43 +02:00
Fredrik Johansson
b9561b05a5 Add choice-based events with a resolution modal
Standard/kaos events can now present 2 options instead of a fixed
effect, pausing new event triggers until the player answers. Adds
4 choice events as a first batch; resources keep accruing while a
choice is pending.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 23:17:48 +02:00
Fredrik Johansson
0efbe9d55b Add Inflytande resource, expand events, and balance the endgame
All checks were successful
Docker / build-and-push (push) Successful in 42s
Adds an influence currency that scales with follower count and a new
"exert influence" action to trade it for secrecy, uncaps recruiting
with scaling cost, adds a late-game Andakt sink, and makes hemlighet
drain scale with dread/ritual progress so the endgame carries real
risk. Includes a Vitest suite that simulates play to check balance,
which caught the influence-accrual rate being too slow to be useful
early game.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 17:28:32 +02:00
Fredrik Johansson
fd457ff312 Add .env.example for docker-compose port/image overrides
All checks were successful
Docker / build-and-push (push) Successful in 37s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-07 23:51:07 +02:00
Fredrik Johansson
482fef15ac Fix z-index: help modal and overlay above Leaflet (z-index 1001/1000)
All checks were successful
Docker / build-and-push (push) Successful in 48s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-07 23:36:37 +02:00
Fredrik Johansson
5fcb339408 Add help modal, changelog, map visits, Dockerfile, CI
- Help modal (? button or keyboard shortcut): how-to-play in Swedish,
  flavor text, full changelog sourced from src/data/version.ts
- src/data/version.ts: versioned changelog entries, in-universe Malmö voice
- Map zone clicks: each location on the Leaflet map is now clickable.
  Unlocked cult areas give resources + log entries. Locked locations show
  lore hints. 30s cooldown per location so it's a decision, not a spam button.
- Dockerfile + nginx.conf + docker-compose.yml (port 5684)
- Gitea CI workflow (identical to 2048 — derives image from repo path, needs
  TKNTKN secret, pushes :latest and :sha tags)
- README.md with mechanics summary and docker instructions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-07 23:31:37 +02:00
Fredrik Johansson
f5776f269b Add lore depth, fix recruit click bug, add localStorage save
- 20+ new events drawing from Anders Fager, Kult, and Call of Cthulhu:
  ICA cashiers who never blink, SJ trains stopping in non-existent tunnels,
  Kult lictors as city officials, death servants finishing lectures, Deep Ones,
  investigators dreaming about us, stars being right over Lund Observatory
- Rewrite upgrade descriptions to match the register: mundane detail,
  matter-of-fact horror, no melodrama
- Add a new mid-game upgrade (Paktens Förnyelse) to smooth the progression
- Fix recruit button: was destroying DOM every 30fps tick, killing mousedown→click
  events; now only rebuilds when availability/affordability actually changes
- Fix double andakt deduction in recruit effect
- Fix map growing over log (proper flex constraints)
- Add localStorage save/load with versioned key (SAVE_VERSION bump invalidates
  old saves); autosaves every 10s and on upgrade purchase, clears on restart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-07 23:25:44 +02:00
Fredrik Johansson
d091e7382a Fix recruit: always available, scaling cost; log newest-first at top
recruit_neighbor was gated behind !first_meeting so it vanished after
the first upgrade. Now a single repeatable recruit with scaling cost.
Log scrolls to top on new entries so most recent is always visible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-07 23:13:54 +02:00
Fredrik Johansson
2c135d57f2 Increase contrast across the board — text, dims, accents, borders
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-07 23:11:11 +02:00
Fredrik Johansson
68a378bdd4 Initial commit — Djupet
Idle cult management game set in Malmö, Sweden. Manage Troende,
Andakt, Dread, Hemlighet and Kaos while completing the Grand Ritual
before investigators shut you down. Lovecraftian flavour, Henderson-
tier chaos events, OSM/Leaflet map with dread spread markers across
Rosengård, Värnhemstorget, Turning Torso and Øresundsbron.

Vanilla TypeScript + Vite, no framework.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-07 23:06:00 +02:00