From 3cd8dcecfaef6c5921bba4da21c32a8cb3405b06 Mon Sep 17 00:00:00 2001 From: Kamil Krzywda Date: Tue, 13 Oct 2026 18:58:43 +0000 Subject: [PATCH] Stop printing the static parent-country code in the region hover tooltip and dossier label (v0.18.0) --- CHANGELOG.md | 3 +++ package.json | 2 +- src/App.tsx | 9 +++++---- src/components/WorldMap.tsx | 22 +++++++++++----------- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a72c4ee..9f63128 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All notable changes to **History** are listed here, newest first. +## v0.18.0 — 2026-10-13 18:54 +- **Fixed a stale-owner display bug: the region hover tooltip and the dossier "Selected" label no longer print the static parent-country code (e.g. "FRA").** The GeoJSON `properties.parent` is a *static geographic-origin* field that never updates when a country is taken, yet it was rendered in the hover tooltip (as a sub-line and as a title fallback) and in the dossier's `Selected:` label (as a `(FRA)` suffix) — so a sub-region of a transferred country still displayed the old country's code next to the (correct) new owner. The tooltip now shows only the region name + the live owner chip (from the RegionMap) + key stats, and the dossier label shows only the region name. Ownership resolution still keys on `properties.parent` (unchanged) — only the display of it was removed. + ## v0.17.0 — 2026-10-13 15:13 - **Filled the no-one's-land left between merged sub-regions (Part of #16).** The v0.14 coarsening's boolean dissolves left slivers of each country's landmass inside no region — measured at **≈ 3.90M km² globally** (the union of a country's regions covered only ~98% of its landmass). The new `scripts/fill-gaps.mjs` (`npm run fill:regions`) closes them: per country it computes the gap (`landmass − union(its regions)`, `@turf/difference`+`union`), drops slivers < **25 km²** (66,637 of them — sub-pixel on the map), and assigns each remaining piece to the **nearest region** (centroid distance) as an appended MultiPolygon part. **2,696,811 km²** of no-one's-land was filled into **1,575 regions** (+6,768 parts: 5,026 → 11,794), leaving **63,889 km²** residual (**98.4% reduction** — the rest is coastline digitization fuzz and 14 tiny border-band overlap artifacts, see below). The named "messy" regions absorb their surroundings: **SI-048 Kočevje (SVN) 16,692 → 19,816 km² (57 → 90 parts)**, **MK-36 Kavadarci (MKD) 21,297 → 25,190 km² (8 → 17)**, **AZ-AGC Ağcabədi (AZE) 18,657 → 32,065 km² (7 → 14)**; the biggest single fills are **AQ-X01~ (Antarctica) +195,351 km²**, **CA-NU (Nunavut) +143,447**, **AQ-X02~ +142,615**, **CL-MA (Magallanes) +81,806**, **US-AK (Alaska) +63,830**, **CA-NT (NWT) +46,333**, **GL-UO (Kommuneqarfiup) +41,971**, **RU-KAM (Kamchatka) +41,911**. - **Correct, not just greedy: clipping, hole policy, dedup.** Each gap piece is clipped sequentially against (a) all *other countries'* regions, (b) its own country's existing regions, and (c) pieces already appended (bbox-touching) — so a piece straddling a border is split, and no piece can double-cover another region's area (**1,149,841 km² of foreign overhang removed** this way; 0 clip failures). **FR-57 Moselle (FRA) gains nothing on purpose**: its apparent gap was a cross-border phantom consumed by the neighbor clip — correct behavior. Holes follow a keep-or-drop policy: a gap hole whose centroid matches a **pre-existing hole** (within 10 km) or lies inside another country's landmass is kept, otherwise it's a phantom and dropped — so the **KZ-KZY Aral hole survives** (5,858 km² planar, the file's only hole; 5,875 km² of water kept open). A global dedup set guarantees each cleaned piece is appended at most once. diff --git a/package.json b/package.json index 0a29187..25bbe35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "history", - "version": "0.17.0", + "version": "0.18.0", "private": true, "type": "module", "description": "AI-driven alternate-history simulator — the LLM is the world engine (Pax Historia style).", diff --git a/src/App.tsx b/src/App.tsx index 306b4a7..a704bf4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -590,8 +590,10 @@ function GameScreen({ // Which nation's dossier to show. Defaults to the player; remounts per game. const [viewingId, setViewingId] = useState(game.playerNationId); // When the dossier target was set by a map click, remember which sub-region - // (its own name + parent country) was clicked, for a small label in the - // dossier. Cleared when the user picks a nation via the manual Inspect select. + // was clicked, for a small label in the dossier. The label shows only the + // region's name — the static parent-country code (which never updates on a + // transfer) is no longer displayed, though the info object still carries it. + // Cleared when the user picks a nation via the manual Inspect select. const [selectedRegion, setSelectedRegion] = useState<{ parent?: string; name?: string } | null>(null); const focusNation = useCallback( (id: string, info?: { parent?: string; name?: string }) => { @@ -779,8 +781,7 @@ function GameScreen({ {selectedRegion && (
- Selected: {selectedRegion.name ?? selectedRegion.parent ?? 'region'} - {selectedRegion.parent ? ` (${selectedRegion.parent})` : ''} + Selected: {selectedRegion.name ?? 'region'}
)} diff --git a/src/components/WorldMap.tsx b/src/components/WorldMap.tsx index 1fc350b..30b407e 100644 --- a/src/components/WorldMap.tsx +++ b/src/components/WorldMap.tsx @@ -174,19 +174,20 @@ function statRow(label: string, value?: number): string { } /** - * Compact hover tooltip: the sub-region's name, its parent country (ISO_A3), its - * owner (color-chipped), and 1–2 key stats. When the parent country has no - * owning nation, a minimal "No owner" card is shown instead. + * Compact hover tooltip: the sub-region's name, its **current owner** + * (color-chipped), and 1–2 key stats. When the region's country has no owning + * nation, a minimal "No owner" card is shown instead. The static + * parent-country code (`properties.parent`) is deliberately NOT printed here — + * it never updates when ownership is transferred, so only the live owner chip + * (resolved from the RegionMap) is shown. */ -function hoverHtml(subRegionName: string, parentCode: string, region?: RegionOwner, nation?: Nation): string { +function hoverHtml(subRegionName: string, region?: RegionOwner, nation?: Nation): string { if (!region || !nation) { - return `
${esc(subRegionName || parentCode || 'Unclaimed')}
No owner
`; + return `
${esc(subRegionName || 'Unclaimed')}
No owner
`; } const stats = [statRow('Mil', nation.stats.military), statRow('Eco', nation.stats.economy)].join(''); - const sub = parentCode ? `
${esc(parentCode)}
` : ''; return `
${esc(subRegionName || region.owner)}
- ${sub}
${esc(region.owner)}
${stats}
`; @@ -221,7 +222,7 @@ interface Props { * layer (z-0) behind the floating HUD windows: a dark-navy basemap with subtle * terrain, per-nation stable fills (uniform per country, the choropleth is the * star), thin sub-region borders, a brighter/thicker amber border for the - * player's countries, a hover tooltip (sub-region name + parent country + owner + * player's countries, a hover tooltip (sub-region name + current owner * + key stats), a **click that switches the dossier to the sub-region's parent * country's owning nation** (no popup — see #7), a transient flash when a * country's owner changes (lighting up all its sub-regions), and a per-scenario @@ -355,9 +356,8 @@ export default function WorldMap({ const onHover = (e: maplibregl.MapLayerMouseEvent) => { const f = e.features?.[0]; if (!f) return; - const p = f.properties as { name?: string; regionId?: string; parent?: string }; + const p = f.properties as { name?: string; regionId?: string }; const subId = typeof p?.regionId === 'string' ? p.regionId : ''; - const parent = typeof p?.parent === 'string' ? p.parent : ''; if (subId && subId !== lastHoverId) { lastHoverId = subId; const geo = baseGeoRef.current; @@ -373,7 +373,7 @@ export default function WorldMap({ const nation = region ? nationsRef.current[region.ownerId] : undefined; hoverPopup .setLngLat(e.lngLat) - .setHTML(hoverHtml(p?.name ?? parent ?? subId, parent, region, nation)) + .setHTML(hoverHtml(p?.name ?? subId, region, nation)) .addTo(map); map.getCanvas().style.cursor = 'pointer'; };