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>
This commit is contained in:
Fredrik Johansson
2026-08-01 21:09:43 +02:00
parent aeedf0abb5
commit 899ab72c80
11 changed files with 265 additions and 6 deletions

View File

@@ -18,8 +18,15 @@ const LOCATIONS: Omit<MapMarker, 'dreadLevel'>[] = [
{ id: 'ribersborg',lat: 55.6063, lng: 12.9652, label: 'Ribersborgsstranden' },
{ id: 'davidshall',lat: 55.5963, lng: 13.0021, label: 'Davidshallsgatan' },
{ id: 'stortorget',lat: 55.6047, lng: 13.0038, label: 'Stortorget' },
{ id: 'mollan', lat: 55.5904, lng: 13.0203, label: 'Möllevångstorget' },
{ id: 'universitet', lat: 55.5721, lng: 12.9998, label: 'Malmö universitet' },
];
// Optional tiny preview shown in each location's tooltip — same
// missing-asset-is-fine convention as the character portraits. Path is
// tried once per marker; a 404 just means the tooltip falls back to text.
const THUMB = (id: string): string => `/img/locations/${id}.png`;
type LeafletMap = ReturnType<typeof L.map>;
type LeafletMarker = ReturnType<typeof L.circleMarker>;
@@ -54,7 +61,14 @@ export function initMap(containerId: string, onClick: (id: string) => void): voi
fillColor: '#1a1a2e',
fillOpacity: 0.3,
weight: 1,
}).addTo(map).bindTooltip(loc.label, { className: 'map-tooltip', permanent: false });
}).addTo(map).bindTooltip(
`<div class="map-tooltip-inner">
<img class="map-tooltip-thumb" src="${THUMB(loc.id)}" alt=""
onerror="this.remove()">
<span>${loc.label}</span>
</div>`,
{ className: 'map-tooltip', permanent: false },
);
m.on('click', () => onClick(loc.id));
markers.set(loc.id, m);
}
@@ -71,6 +85,8 @@ export function updateMap(dread: number, areas: { rosengard: boolean; varnhem: b
ribersborg: Math.min(2, Math.floor(dread / 45)),
davidshall: Math.min(1, Math.floor(dread / 70)),
stortorget: Math.min(2, Math.floor(dread / 55)),
mollan: Math.min(2, Math.floor(dread / 48)),
universitet: Math.min(2, Math.floor(dread / 65)),
};
for (const [id, marker] of markers) {